python-模板方法模式
源码地址: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-模板方法模式的更多相关文章
- [python实现设计模式]-2.模板方法模式---把大象关进冰箱.
平时大家上班都很累,为了增加工作中的欢乐气氛,黄页组准备搞个游戏. 游戏的名字是把大象关进冰箱.游戏很简单,需要把指定的物品放进冰箱. 我们都知道,把大象放进冰箱,分3步. 第一步,打开冰箱门,第二步 ...
- 大话设计模式Python实现-模板方法模式
模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟至子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 下面是一个模 ...
- 简介Python设计模式中的代理模式与模板方法模式编程
简介Python设计模式中的代理模式与模板方法模式编程 这篇文章主要介绍了Python设计模式中的代理模式与模板方法模式编程,文中举了两个简单的代码片段来说明,需要的朋友可以参考下 代理模式 Prox ...
- Python笔记:设计模式之模板方法模式
此模式通过一个模板方法来定义程序的框架或算法,通常模板方法定义在基类中,即原始的模板,然后子类就可以根据不同的需要实现或重写模板方法中的某些算法步骤或者框架的某部分,最后达到使用相同模板实现不同功能的 ...
- python 设计模式之模板方法模式
1.模板方法模式定义 模板模式定义如下:定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定的步骤.子类实现的具体方法叫作基本方法,实现对 ...
- .NET责任链模式(混合单例模式,模板方法模式)-----制作与扩展能力验证
.NET责任链模式.单例模式.模板方法模式混用 前言 哇,看到题目挺长的,这个组合型的东西,到底能干啥呢?本篇文章来一起琢磨琢磨,这两天为了团队的软件赶工,我负责的那一块叫:插件管理器.我们团队的成员 ...
- 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)
今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...
- 设计模式(十四)模板方法模式(Template Pattern)
一.引言 提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简 ...
- C#设计模式-模板方法模式
提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下 ...
- C#设计模式系列:模板方法模式(Template Method)
你去银行取款的时候,银行会给你一张取款单,这张取款单就是一个模板,它把公共的内容提取到模板中,只留下部分让用户来填写.在软件系统中,将多个类的共有内容提取到一个模板中的思想便是模板方法模式的思想. 模 ...
随机推荐
- 【kuangbin专题】计算几何_半平面交
1.poj3335 Rotating Scoreboard 传送:http://poj.org/problem?id=3335 题意:就是有个球场,球场的形状是个凸多边形,然后观众是坐在多边形的边上的 ...
- Python大黑阔—url采集+exp验证,带你批量测试
i春秋作家:大木瓜 前言: 最近几天在整理从各处收集来的各种工具包,大大小小的塞满了十几个G的硬盘,无意间发现了一个好几年前的0day.心血来潮就拿去试了一下,没想到真的还可以用,不过那些站点都已经老 ...
- Eleasticsearch启动失败问题解决
问题: [root@dnode1 bin]# ./elasticsearch -d [root@dnode1 bin]# Exception in thread "main" ja ...
- 【xsy2506】 bipartite 并查集+线段树
题目大意:有$n$个点,你需要操作$m$次.每次操作为加入/删除一条边. 问你每次操作后,这$n$个点构成的图是否是二分图. 数据范围:$n,m≤10^5$. 此题并没有强制在线,考虑离线做法. 一条 ...
- #Python学习#python虚拟环境——virtualenv
前言 在Ubuntu系统中,系统一般会默认安装python2.x和3.x,像我近期买的阿里云ECS默认安装了2.7.2和3.5.2,所有pip安装的第三方包都会被放在默认的site-apckages目 ...
- android stdio Error Could not find com.android.tools common 25.2.2
Error:Could not find com.android.tools:common:25.2.2. Searched in the following locations: file:/D:/ ...
- 全网最详细的启动Kafka服务时出现kafka.common.InconsistentBrokerIdException: Configured brokerId 3 doesn't match stored brokerId 1 in meta.properties错误的解决办法(图文详解)
不多说,直接上干货! 问题详情 执行bin/kafka-server-start.sh config/server.properties 时, [kfk@bigdata-pro03 kafka_2.- ...
- 一段奇妙的vim编辑器之旅
一.背景 对于Linux服务器上的操作,我们往往少不了使用vim,而有时候我对vim的使用并没有那么的熟练和深入,这周就深入的学习了vim的使用,包括入门和进阶,先分享给你们,也方便自己以后复习查询. ...
- windows平台,实现录音功能详解
音频处理分为播放和录音两类.对这些处理,微软提供了一些列函数,称之为Waveform Functions.这篇文章讨论录音功能.会对微软提供的函数做简单说明,并对这些函数封装成c++类,再进一步封装成 ...
- redis开机自动服务脚本
1.设置redis.conf中daemonize为yes,确保守护进程开启. 2.编写开机自启动脚本 基本原理为: 系统开机启动时会去加载/etc/init.d/下面的脚本,通常而言每个脚本文件会自定 ...