python设计模式之模版方法设计模式
我们在使用python的flask框架时,可能会经常用到生命周期函数如:before_request, before_first_request,或者信号等,刚开始学的时候就想只要写一个函数,然后加上一个装饰器居然就可以实现这种开挂般的效果,那时感觉这框架代码写得真棒, 再过些时间自己学会阅读框架源码时,在flask源码中的wsgi_app函数里面发现了奥秘,原来是这样写就能实现插入生命周期的效果啊,时间在走知识在涨,不知不觉走进了设计模式的天堂,再猛然看flask框架源码的时候就觉得,原来如此,这不就是模版方法设计模式的具体应用吗?接下来我们来看看什么是模版方法设计模式来揭开它的神秘面纱。
模版方法设计模式GOF官方的解释是: 定义一个操作中的算法的骨架(稳定), 而将一些步骤(变化)延迟到子类中。 使得子类可以不改变(复用)一个算法的结构即可重定义该算法的某些特定步骤。
模版方法设计模式的框架图如下:

可以看到在抽象类中定义了一系列固定流程的方法, 而在子类中去重写或者实现具体的某些步骤。
接下来我们用丐版的Flask来演示模版方法设计模式的精髓,声明flask框架并不是这样实现的,只是含有模版设计模式的思想, 我们的演示只是把这思想展示出来。
01、没有用设计模式Flask
class Flask:
def before_request(self):
pass
def request(self):
pass
def context(self):
print("我在存储上下文")
def response(self):
pass
def clear(self):
print("我在清除上下文")
class Application(Flask):
def before_request(self):
print("我在煮饭前加了一个蛋")
def request(self):
print("我正在吃饭")
def response(self):
print("终于吃好了")
def run(self):
self.before_request()
self.request()
self.context()
self.request()
self.clear()
Application().run()
我们发现,run方法执行的步骤是固定的,这样每个app继承Flask的时候都要实现一个run方法,加重了app开发者的负担,因为run主程序的步骤是固定的,我们把run方法的实现移到抽象类Flask中,看一下效果。
02、 用了模版设计模式的Flask
class Flask:
def before_request(self):
pass
def request(self):
pass
def context(self):
print("我在存储上下文")
def response(self):
pass
def clear(self):
print("我在清除上下文")
def run(self):
self.before_request()
self.request()
self.context()
self.request()
self.clear()
class Application(Flask):
def before_request(self):
print("我在煮饭前加了一个蛋")
def request(self):
print("我正在吃饭")
def response(self):
print("终于吃好了")
Application().run()
这里我们就是把主程序run方法移动到抽象类Flask中,这时作为我们开发者,我们只要实现具体的步骤如,before_request和request等就可以了,这样大大减轻了开发者负担。
03、什么时候使用模版方法设计模式
在构建过程中,对于某一项任务,它通常有稳定的整体操作结构, 但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。在这个时候模版方法设计模式将会是你很好的一个选择。
04、总结
模版方法设计模式是一种非常基础性的设计模式, 在面向对象系统中有大量的应用。它用最简洁的机制(多态)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
除了可以灵活应对子步骤的变化外, “不要调用我, 让我来调用你”的反向控制结构是模版方法设计模式的典型应用。
最后还是奉上设计模式的8大基本设计原则:
- 依赖倒置原则(DIP)
- 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定) 。
- 抽象(稳定)不应该依赖于实现细节(变化) ,实现细节应该依赖于抽象(稳定)。
- 开放封闭原则(OCP)
- 对扩展开放,对更改封闭。
- 类模块应该是可扩展的,但是不可修改。
- 单一职责原则(SRP)
- 一个类应该仅有一个引起它变化的原因。
- 变化的方向隐含着类的责任。
- Liskov 替换原则(LSP)
- 子类必须能够替换它们的基类(IS-A)。
- 继承表达类型抽象。
- 接口隔离原则(ISP)
- 不应该强迫客户程序依赖它们不用的方法。
- 接口应该小而完备。
- 优先使用对象组合,而不是类继承
- 类继承通常为“白箱复用”,对象组合通常为“黑箱复用” 。
- 继承在某种程度上破坏了封装性,子类父类耦合度高。
- 而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。
- 封装变化点
- 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
- 针对接口编程,而不是针对实现编程
- 不将变量类型声明为某个特定的具体类,而是声明为某个接口。
- 客户程序无需获知对象的具体类型,只需要知道对象所具有的接口。
- 减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案
python设计模式之模版方法设计模式的更多相关文章
- JS常用的设计模式(10)——模版方法模式
模式方法是预先定义一组算法,先把算法的不变部分抽象到父类,再将另外一些可变的步骤延迟到子类去实现.听起来有点像工厂模式( 非前面说过的简单工厂模式 ). 最大的区别是,工厂模式的意图是根据子类的实现最 ...
- 设计模式 笔记 模版方法模式 Template Method
//---------------------------15/04/28---------------------------- //TemplateMethod 模版方法模式----类行为型模式 ...
- 设计模式之模版方法模式(Template Method Pattern)
一.什么是模版方法模式? 首先,模版方法模式是用来封装算法骨架的,也就是算法流程 既然被称为模版,那么它肯定允许扩展类套用这个模版,为了应对变化,那么它也一定允许扩展类做一些改变 事实就是这样,模版方 ...
- JAVA设计模式之模版方法模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式 ...
- 黑马程序员——JAVA基础之抽象和接口 , 模版方法设计模式
------- android培训.java培训.期待与您交流! ---------- 抽象定义: 抽象就是从多个事物中将共性的,本质的内容抽取出来. 例如:狼 ...
- java设计模式之模版方法模式以及在java中作用
模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有 ...
- Head First 设计模式 —— 09. 模版方法 (Template Method) 模式
模板方法模式 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. P289 特点 主导算法框架,并且保护这个算法 P28 ...
- Python设计模式——模版方法模式
1.模版方法模式 做题的列子: 需求:有两个学生,要回答问题,写出自己的答案 #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class Stude ...
- [Python设计模式] 第10章 怎么出试卷?——模版方法模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 小时候数学老师的随堂测验,都是老师在黑板上写题目,学生在下边抄,然后再做题 ...
随机推荐
- Java实现 LeetCode 372 超级次方
372. 超级次方 你的任务是计算 ab 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出. 示例 1: 输入: a = 2, b = [3] 输出: 8 示例 2: ...
- Java实现字符串的包含
1 问题描述 给定一长字符串A和一短字符串B.请问,如何最快地判断出短字符串B中的所有字符是否都在长字符串A中?请编写一个判断函数实现此功能. 为简单起见,假设输入的字符串只包含小写英文字母.下面举几 ...
- java实现第七届蓝桥杯机器人塔
机器人塔 X星球的机器人表演拉拉队有两种服装,A和B. 他们这次表演的是搭机器人塔. 类似: A B B A B A A A B B B B B A B A B A B B A 队内的组塔规则是: A ...
- PAT 部分A+B
正整数A的“DA(为 1 位整数)部分”定义为由A中所有DA组成的新整数PA,例如:给定A=3862767,DA=6,则A的“6 部分”PA是 66,因为A中有 2 个 6. 现给定A,DA,B, ...
- (二)SQL注入常用的内置函数整理(以MySql为例)
[1]@@datadir 函数作用:返回数据库的存储目录构造SQL语句 select @@datadir; [2]@@version_compile_os 函数作用:查看服务器的操作系统SQL语句 ...
- 【JVM故事】了解JVM的结构,好在面试时吹牛
class文件格式 参考上一篇文章<[JVM故事]一个Java字节码文件的诞生记>,后续还会专门讲解class文件的内部结构. 数据类型 jvm包括两种数据类型,基本类型和引用类型. 基本 ...
- 你真的了解EF吗?关于EntityFramework的高级优化
接上一篇文章.现在写程序,做项目不是说功能做完就完事了,在平常的开发过程中对于性能的考虑也是极其重要的. 关于ef的那些事,今天就来说说吧.首先必须得知道.net ef在程序中的五种状态变化过程与原理 ...
- Flask简单http接口实现
# flask demo from flask import Flask, request app = Flask(__name__) # http://127.0.0.1:8080 @app.rou ...
- 氦元素 - CUBA 应用程序新样式主题
CUBA 框架一直以来定位的目标是业务系统的开发.业务系统的界面通常是给后台员工使用的,看重的是功能实现.多年来,界面外观和样式并不是后台管理系统的主要关注点,界面中的控件也更紧凑,唯一的原因 ...
- CSS3弹性布局内容对齐(justify-content)属性使用详解
内容对齐(justify-content)属性应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐. 该操作发生在弹性长度以及自动边距被确定后. 它用来在存在剩余空间时如何加以分配 ...