源码地址:https://github.com/weilanhanf/PythonDesignPatterns

说明:

模板方法模式时行为模式中比较简单的设计模式之一。模板方法关注这样的一类行为:该类行为在执行过程中拥有大致相同的动作次序,只是动作在实现的具体细节上有所差异。例如:泡茶和泡咖啡,泡茶:把水煮沸,沸水加入茶叶,把倒进杯子。泡咖啡:把水煮沸,用沸水冲咖啡粉,把咖啡倒进杯子。这样看来泡茶和泡咖啡的三个步骤基本相似。我们可以报这一类行为抽象成一个算法,并将其中的动作序列按1其先后顺序也抽象出来作为该算法的一些步骤。至于这些步骤的实现细节,则有算法的子类去实现。

模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法模式 是一种基于继承的代码复用技术 ,将一些复杂流程的实现步骤封装在一系列基本方法中 ,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。

模板方法模式的结构

模板方法模式包含以下两个角色: AbstractClass(抽象类) ConcreteClass(具体子类)

模板方法模式的实现:

模板方法 (Template Method)

基本方法 (Primitive Method) :1、抽象方法(Abstract Method)2、 具体方法(Concrete Method) 3、钩子方法(Hook Method) :“挂钩”方法和空方法

实例:

投资股票是种常见的理财方式,我国股民越来越多,实时查询股票的需求也越来越大。今天,我们通过一个简单的股票查询客户端来认识一种简单的设计模式:模板模式。
根据股票代码来查询股价分为如下几个步骤:登录、设置股票代码、查询、展示。

#构造如下的虚拟股票查询器:
class StockQueryDevice():
stock_code=""
stock_price=0.0
def login(self,usr,pwd):
pass
def setCode(self,code):
self.stock_code=code
def queryPrice(self):
pass
def showPrice(self):
pass #根据不同的查询机构和方式来通过继承的方式实现其的股票查询器类。
#WebA和WebB的查询器类可以构造如下:
class WebAStockQueryDevice(StockQueryDevice):
def login(self,usr,pwd):
if usr=="myStockA" and pwd=="myPwdA":
print "Web A:Login OK... user:%s pwd:%s"%(usr,pwd)
return True
else:
print "Web A:Login ERROR... user:%s pwd:%s"%(usr,pwd)
return False
def queryPrice(self):
print "Web A Querying...code:%s "%self.stock_code
self.stock_price=20.00
def showPrice(self):
print "Web A Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price)
class WebBStockQueryDevice(StockQueryDevice):
def login(self,usr,pwd):
if usr=="myStockB" and pwd=="myPwdB":
print "Web B:Login OK... user:%s pwd:%s"%(usr,pwd)
return True
else:
print "Web B:Login ERROR... user:%s pwd:%s"%(usr,pwd)
return False
def queryPrice(self):
print "Web B Querying...code:%s "%self.stock_code
self.stock_price=30.00
def showPrice(self):
print "Web B Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price) #在场景中,想要在网站A上查询股票
if __name__=="__main__":
web_a_query_dev=WebAStockQueryDevice()
web_a_query_dev.login("myStockA","myPwdA")
web_a_query_dev.setCode("")
web_a_query_dev.queryPrice()
web_a_query_dev.showPrice()

打印结果:

Web A:Login OK... user:myStockA pwd:myPwdA
Web A Querying...code:12345 
Web A Stock Price...code:12345 price:20.0

但是发现每次操作,都会调用登录,设置代码,查询,展示这几步,是不是有些繁琐?既然有些繁琐,何不将这几步过程封装成一个接口。由于各个子类中的操作过程基本满足这个流程,所以这个方法可以写在父类中。

class StockQueryDevice():
stock_code=""
stock_price=0.0
def login(self,usr,pwd):
pass
def setCode(self,code):
self.stock_code=code
def queryPrice(self):
pass
def showPrice(self):
pass def operateQuery(self, usr, pwd, code):
if not self.login(usr, pwd):
return False
self.setCode(code)
self.queryPrice()
self.showPrice()
return True class WebAStockQueryDevice(StockQueryDevice):
def login(self,usr,pwd):
if usr=="myStockA" and pwd=="myPwdA":
print("Web A:Login OK... user:%s pwd:%s"%(usr,pwd))
return True
else:
print("Web A:Login ERROR... user:%s pwd:%s"%(usr,pwd))
return False
def queryPrice(self):
print("Web A Querying...code:%s "%self.stock_code)
self.stock_price=20.00
def showPrice(self):
print("Web A Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price))
class WebBStockQueryDevice(StockQueryDevice):
def login(self,usr,pwd):
if usr=="myStockB" and pwd=="myPwdB":
print("Web B:Login OK... user:%s pwd:%s"%(usr,pwd))
return True
else:
print("Web B:Login ERROR... user:%s pwd:%s"%(usr,pwd))
return False
def queryPrice(self):
print("Web B Querying...code:%s "%self.stock_code)
self.stock_price=30.00
def showPrice(self):
print("Web B Stock Price...code:%s price:%s"%(self.stock_code,self.stock_price)) if __name__=="__main__":
web_a_query_dev=WebAStockQueryDevice()
web_a_query_dev.operateQuery("myStockA","myPwdA","")

打印结果相同:

Web A:Login OK... user:myStockA pwd:myPwdA
Web A Querying...code:12345
Web A Stock Price...code:12345 price:20.0

模式优点

在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序 。提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为。 可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行 更换和增加新的子类很方便,符合单一职责原则和开闭原则

模式缺点

需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统会更加庞大,设计也会更加抽象(可结合桥接模式)

模式适用环境

一次性实现一个算法的不变部分,并将可变的行为留给子类来实现 。各子类中公共的行为应被提取出来,并集中到一个公共父类中,以避免代码重复。 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制

另外:

在模板方法模式中,子类不显式调用父类的方法,而是通过覆盖父类的方法来实现某些具体的业务逻辑,父类控制对子类的调用,这种机制被称为好莱坞原则(Hollywood Principle),好莱坞原则的定义为:“不要给我们打电话,我们会给你打电话(Don‘t call us, we’ll call you)”。在模板方法模式中,好莱坞原则体现在:子类不需要调用父类,而通过父类来调用子类,将某些步骤的实现写在子类中,由父类来控制整个过程。

python-模板方法模式的更多相关文章

  1. [python实现设计模式]-2.模板方法模式---把大象关进冰箱.

    平时大家上班都很累,为了增加工作中的欢乐气氛,黄页组准备搞个游戏. 游戏的名字是把大象关进冰箱.游戏很简单,需要把指定的物品放进冰箱. 我们都知道,把大象放进冰箱,分3步. 第一步,打开冰箱门,第二步 ...

  2. 大话设计模式Python实现-模板方法模式

    模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟至子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 下面是一个模 ...

  3. 简介Python设计模式中的代理模式与模板方法模式编程

    简介Python设计模式中的代理模式与模板方法模式编程 这篇文章主要介绍了Python设计模式中的代理模式与模板方法模式编程,文中举了两个简单的代码片段来说明,需要的朋友可以参考下 代理模式 Prox ...

  4. Python笔记:设计模式之模板方法模式

    此模式通过一个模板方法来定义程序的框架或算法,通常模板方法定义在基类中,即原始的模板,然后子类就可以根据不同的需要实现或重写模板方法中的某些算法步骤或者框架的某部分,最后达到使用相同模板实现不同功能的 ...

  5. python 设计模式之模板方法模式

    1.模板方法模式定义 模板模式定义如下:定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定的步骤.子类实现的具体方法叫作基本方法,实现对 ...

  6. .NET责任链模式(混合单例模式,模板方法模式)-----制作与扩展能力验证

    .NET责任链模式.单例模式.模板方法模式混用 前言 哇,看到题目挺长的,这个组合型的东西,到底能干啥呢?本篇文章来一起琢磨琢磨,这两天为了团队的软件赶工,我负责的那一块叫:插件管理器.我们团队的成员 ...

  7. 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)

    今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...

  8. 设计模式(十四)模板方法模式(Template Pattern)

    一.引言 提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简 ...

  9. C#设计模式-模板方法模式

    提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下 ...

  10. C#设计模式系列:模板方法模式(Template Method)

    你去银行取款的时候,银行会给你一张取款单,这张取款单就是一个模板,它把公共的内容提取到模板中,只留下部分让用户来填写.在软件系统中,将多个类的共有内容提取到一个模板中的思想便是模板方法模式的思想. 模 ...

随机推荐

  1. 【Vue】【Router】手动跳转用 this.$router.push() 时 $router 未定义的问题

    初入Vue,手写路由跳转时的问题: toXxxRoute: () => { this.$router.push({'path': '/xxx', 'name': 'xxx'}) } 由于使用了箭 ...

  2. vue教程1-07 模板和过滤器

    vue教程1-07 模板和过滤器 一.模板 {{msg}} 数据更新模板变化 {{*msg}} 数据只绑定一次 {{{msg}}} HTML转意输出 <!DOCTYPE html> < ...

  3. 关于并发用户数的思考-通过PV量换算并发

    首先介绍一下pv量:PV(访问量):即Page View, 即页面浏览量或点击量,用户每次刷新即被计算一次.UV(独立访客):即Unique Visitor,访问您网站的一台电脑客户端为一个访客.00 ...

  4. Oracle VM VirtualBox启动后莫名奇妙的报错

    VirtualBox软件无法启动: 参考解决:http://blog.csdn.net/a_ssimi/article/details/52002939 修改兼容性:http://blog.csdn. ...

  5. android(java) 开发过程中经验及总结记录

    android(java) 开发过程中经验及总结记录

  6. Prototype原型模式(创建型模式)

    1.原型模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只有一 ...

  7. 用SpringSecurity从零搭建pc项目-02

    参照这一篇文章吧,比如你不需要做的那么通用,取其中一部分代码即可. https://www.cnblogs.com/lihaoyang/p/8491792.html

  8. Linux 部署 ASP.NET Core 的一些问题记录

    异常错误: 关闭 IP6 #修改 vi /etc/sysctl.conf # 添加如下三条设置    net.ipv6.conf.all.disable_ipv6 = 1    net.ipv6.co ...

  9. html中引入调用另一个公用html模板文件的方法

    html中引入调用另一个公用html模板文件的方法 https://www.w3h5.com/post/53.html 这里我使用jquery的方法 <body> <div id=& ...

  10. Linux信号和trap命令的使用

    目录 信号介绍 信号列表 控制信号 Ctrl+c显示指定内容 使Ctrl+c无任何操作 处理多个信号 处理所有信号 恢复信号 实现跳板机(实例) 信号介绍 运行Shell脚本时,如果按下快捷键Ctrl ...