细说Python设计模式之模板方法模式(封装算法)
文章目录
- 定义模板方法模式
- 适用场景
- 日常例子理解该模式
- 了解模板方法设计模式
- 模板方法模式的UML类图
- 现实中的模板方法模式
- 模板方法模式——钩子
- 好莱坞原则与模板方法
- 模板方法的优缺点
- 问答
定义模板方法模式
行为模式主要关注对象的响应性。它处理对象之间的交互以实现更强大的功能。模板方法模式是一种行为设计模式,通过一种称为模板方法的方式来定义程序框架或算法。例如,你可以将制作饮料的步骤定义为模板方法中的算法。模板方法模式还通过将这些步骤中的一些实现推迟到子类来帮助重新定义或定制算法的某些步骤。这意味着子类可以重新定义自己的行为。例如,在这种情况下,子类可以使用制作饮料的模板方法来实现沏茶的步骤。需要重点关注的是,步骤的改变(如子类所做的)并不影响原始算法的结构。因此,在模板方法模式中的子类可以通过覆盖来创建不同的行为或算法。
在讨论模板方法模式的时候,按照软件开发术语来说,我们可以使用抽象类来定义算法的步骤。这些步骤在模板方法模式的上下文中也称为原始操作。这些步骤通常用抽象方法定义,而模板方法则用来定义算法。ConcreteClass(子类化抽象类)则用来实现算法中子类的特定步骤。
适用场景
- 当多个算法或类实现类似或相同逻辑的时候;
- 在子类中实现算法有助于减少重复代码的时候;
- 可以让子类利用覆盖实现行为来定义多个算法的时候;
日常例子理解该模式
煮咖啡步骤:
- 烧开水。
- 研磨咖啡豆。
- 把它倒在咖啡杯里。
- 将糖和牛奶加入杯中。
- 搅拌,然后咖啡就做好了。
柠檬茶步骤://
- 烧开水
- 泡茶
- 将茶水倒入杯中
- 向茶水中加入柠檬
- 搅拌,一杯柠檬茶做好了。
分析这两个制作过程,你会发现两者基本一致。在这种情况下,模板方法模式就有了用武之地了。
了解模板方法设计模式
模板方法的主要意图:
- 使用基本操作定义算法的框架;
- 重新定义子类的某些操作,而无需修改算法的结构
- 实现代码重用并避免重复工作
- 利用通用接口或实现。
例子:
from abc import ABCMeta, abstractmethodclass Compiler(metaclass=ABCMeta):@abstractmethoddef collectSource(self):pass@abstractmethoddef compileToObject(self):pass@abstractmethoddef run(self):passdef compileAndRun(self):self.collectSource()self.compileToObject()self.run()class iOSCompiler(Compiler):def collectSource(self):print("Collecting Swift Source Code")def compileToObject(self):print("Compiling Swift code to LLVM bitcode")def run(self):print("Program runing on runtime environment")iOS = iOSCompiler()
iOS.compileAndRun()
输出:
模板方法模式的UML类图
模板方法模式的主要角色有:抽象类、具体类、模版方法和客户端。
有4个主要参与者:
- AbstractClass:在抽象方法的帮助下定义算法的操作或步骤。这些步骤将被具体子类覆盖。
- template_method():定义算法的框架。在模板方法中调用抽象方法定义的多个步骤来定义序列或算法本身。
- ConcreteClass:实现(由抽象方法定义的)步骤,来执行算法子类的特定步骤。
例子:
from abc import ABCMeta, abstractmethodclass AbstractClass(metaclass=ABCMeta):def __init__(self):pass@abstractmethoddef operation1(self):pass@abstractmethoddef operation2(self):passdef template_method(self):print("Defining the Algorithm. Operation1 follows Operation2")self.operation2()self.operation1()
现实中的模板方法模式
用一个非常容易理解的案例来实现模板方法模式。想象一个旅行社的例子,例如Dev Travels。那么,他们通常是如何运作的呢? 他们定义了各种旅游路线,并提供度假套装行程。一个行程套餐本质上是你作为客户允诺的一次旅行。旅行还涉及一些详细信息,如游览的地点、交通方式和与旅行有关的其他因素。当然,同样的行程可以根据客户的需求进行不同的定制。这种情况下,模板方法模式就有了用武之地,不是吗?
例子:
from abc import abstractmethod, ABCMeta# 抽象对象由Trip类表示。它是一个接口(Python的抽象基类),定义了不同日子使用的交通方式和参观的地点等细节;
class Trip(metaclass=ABCMeta):# setTransport是一个抽象方法,它由ConcreteClass实现,作用是设置交通方式;@abstractmethoddef setTransport(self):pass# day1()、day2()、day3()抽象方法定义了特定日期所参观的地点;@abstractmethoddef day1(self):pass@abstractmethoddef day2(self):pass@abstractmethoddef day3(self):pass@abstractmethoddef returnHome(self):pass# itinerary()模板方法创建完整的行程(即算法,在本例中为旅行)。旅行的序列为,首先定义交通模式,然后是每天要参观的地点,以及returnHome。def itinerary(self):self.setTransport()self.day1()self.day2()self.day3()self.returnHome()# 这两个具体类代表游客根据他们的选择和兴趣所进行的两次不同的旅行;
# VeniceTrip和MaldivesTrip都实现了setTransport()、day1()、day2()、day3()和returnHome()。
class VeniceTrip(Trip):def setTransport(self):print("Take a boat and find your way in the Grand Canal")def day1(self):print("Visit St Mark's Basilica in st Mark's Square")def day2(self):print("Appreciate Doge's Palace")def day3(self):print("Enjoy the food near the Rialto Bridge")def returnHome(self):print("Get souvenirs for friends and get back")class MaldivesTrip(Trip):def setTransport(self):print("On foot, on any island, Wow!")def day1(self):print("Enjoy the marine life of Banana Reef")def day2(self):print("Go for the water sports and snorkeling")def day3(self):print("Relax on the beach and enjoy the sun")def returnHome(self):print("Don't feel like leaving the beach")# TravelAgency类代表该示例中的Client对象;
# 它定义了arrange_trip()方法,让客户选择历史旅行或海滩旅行;
# 根据旅游者的选择,相应的类将被实例化。
# 这个对象然后调用itinerary()模板方法,并根据客户的选择为游客安排相应的旅行。
class TravelAgency:def arrange_trip(self):choice = input("What kind of place you'd like to go historical or to a beach")if choice == "historical":self.trip = VeniceTrip()self.trip.itinerary()if choice == "beach":self.trip = MaldivesTrip()self.trip.itinerary()TravelAgency().arrange_trip()
模板方法模式——钩子
钩子是在抽象类中声明的方法,它通常被赋予一个默认实现。钩子背后的思想是为子类提供按需钩取算法的能力。但是,它并不强制子类使用钩子,它可以很容易地忽略这一点。
例如,在饮料的例子中,我们可以添加一个简单的钩子,看看调味品是否需要与茶或咖啡一起提供,具体视客户的意愿而定。
在旅行社示例中,也可以使用钩子。现在,如果我们有几个老年游客,他们可能不想在为期3天的旅行中每天都出去游玩,因为他们可能很容易疲劳。在这种情况下,我们可以开发一个钩子,以确保第2天的旅程缩短,这意味着他们可以去附近的几个地方游览,然后继续参与第3天的旅行计划。
通常情况下,当子类必须提供实现时,我们会使用抽象方法,并且当子类的实现不是强制的时候,我们就会使用钩子。
好莱坞原则与模板方法
好莱坞原则是一种设计原则,即不要给我们打电话,我们会打给你的。它来自好莱坞哲学,如果有适合演员的角色,影棚会给演员打电话。
在面向对象的世界中,我们允许低层组件使用好莱坞原则将自己挂入系统中。然而,高层组件确定低层系统的使用方式,以及何时需要它们。换句话说,高层组件对待低层组件的方式也是不要给我们打电话,我们会打电话给你。
这涉及模板方法模式,在这个意义上,它是高级抽象类,它安排定义算法的步骤。根据算法的工作方式,通过调用低层类来定义各个步骤的具体实现。
模板方法的优缺点
优点
- 没有重复代码
- 由于模板方法模式使用继承而不是合成,因此能够对代码进行重用。所以,只有为数不多的几个方法需要重写。
- 灵活性允许子类决定如何实现算法中的步骤。
缺点
- 调试和理解模板方法模式中的流程序列有时会令人困惑。你最终实现的方法可能是一个不应该实现的方法,或根本没有实现抽象方法。文档和严格的错误处理必须由程序员完成。
- 模板框架的维护可能是一个问题,因为任何层次(低层或高层)的变更都可能对现实造成干扰。因此使用模板方法模式可能使维护变得异常痛苦。
问答
1. 是否应该禁止底层组件调用更高层组件中的方法?
**答:**不,底层组件当然通过继承来调用高层组件。然而,程序员需要注意的是,不要出现循环依赖性,即高层组件和底层组件彼此依赖。
2.策略模式是否类似于模板模式?
答:策略模式和模板模式都是封装算法。
模板取决于继承,而策略使用组合。模板方法模式是通过子类话在编译时进行算法选择,而策略模式是在运行时进行选择。
细说Python设计模式之模板方法模式(封装算法)相关推荐
- 模板方法模式——封装算法
目录 1 模板方法模式 2 模板方法()模式的UML类图 3 模板方法模式的一个例子:要caffe还是tea 4 好莱坞准则和模板方法模式 4.1 好莱坞准则 4.2 好莱坞准则与模板方法 5 模板方 ...
- Python设计模式之模板方法模式实例详解
1.模板方法模式定义 定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定的步骤. 子类实现的具体方法叫作基本方法,实现对基本方法高度的框 ...
- Python设计模式(四) -- 模板方法模式
模板方法模式 定义 定义了一个算法的步骤,并允许子类别为一个或多个步骤提供其实践方式.让子类别在不改变算法架构的情况下,重新定义算法中的某些步骤 适用场景: 事务处理的步骤具有共性,只是具体实施,根据 ...
- python策略模式包含角色_详解Python设计模式之策略模式
虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用.<设计模式:可复用面向对象软件的基础>一书中有 23 个模式,其中有 16 个在动态语言中"不见了,或者简 ...
- C++设计模式之模板方法模式
模板方法模式 设计模式的定义 模板方法模式详解 背景----柠檬茶和咖啡的的冲泡方式 代码实现咖啡和茶冲泡的类 整理相似点 进一步设计 总结一下 认识模板方法 测试一下 模板方法模式的优点 模板方法的 ...
- 设计模式-04.模板方法模式
设计模式-04.模板方法模式 模板方法模式 定义 介绍 实现 优点 缺点 使用场景 扩展 定义 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板.它的子类 ...
- Python设计模式-中介者模式
Python设计模式-中介者模式 代码基于3.5.2,代码如下; #coding:utf-8 #中介者模式class colleague():mediator = Nonedef __init__(s ...
- python的编程模式-Python设计模式之状态模式原理与用法详解
本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...
- 一篇博客读懂设计模式之---模板方法模式
设计模式之模板方法模式: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 简而言之就是:父类定义了骨架(调用哪些方法及其 ...
最新文章
- 久未更 ~ 一之 —— 关于ToolBar
- python消费datahub_DataHub使用指南-阿里云开发者社区
- mysql loop循环实例_MySql CURSOR+LOOP循环-使用小实例
- springboot项目 tomcat8.x 频繁宕机 原因分析
- echarts 柱状图 ,颜色和显示设置
- mysql 主机不存在_MySQL 当记录不存在时插入,当记录存在时更新
- plsql提示列快捷键_PLsql快捷键
- Flutter进阶—布局一个控件
- python画散点图-python学习之matplotlib绘制散点图实例
- 前缀树(字典树,单词查找树,Trie树)
- 使用windows远程桌面连接ubuntu
- CKeditor与CKfinder的简单配置
- oracle表转换mysql建表语句
- 基于python+django房屋租赁管理系统pycharm源码lw
- 【C语言】#文件操作#有5个学生,每个学生有3门课程的成绩,从键盘输入以上数据(包括学号、姓名、3门课成绩),计算出平均成绩,将原有数据和计算出的平均分数存放在磁盘文件stud中。
- websocket协议与实现原理
- [转]Cisco小失误,大麻烦
- upupoo启动不了 mysql_【upupoo动态桌面壁纸和phpMySQLConsole 0.1哪个好用】upupoo动态桌面壁纸和phpMySQLConsole 0.1对比-ZOL下载...
- 怎么样才能快速有效系统的学好linux?
- 生命的超级能量(宇宙真相)