模板方法——封装算法
概念
- 模板方法通过一种称为模板方法的方式来定义程序框架或者算法
- 使用基本操作定义算法框架
- 重新定义子类某些操作
- 实现代码重用
- 利用通用接口实现
比如:我们封装了制作饮料的算法,那么现在可以用制作饮料的模板方法来实现沏茶。但需要改变步骤。
实现
一个编译器:收集源代码,把源代码编译成目标对象。现在如果需要给ios设备交叉编译:
from abc import ABCMeta, abstractmethod
# 通用编译器接口
class Compiler(object):
@abstractmethod
def collect_Source(self):
pass
@abstractmethod
def compile_to_object(self):
pass
@abstractmethod
def run(self):
pass
def compile_and_run(self):
self.collect_Source()
self.compile_and_run()
self.run()
# ios编译器具体实现
class IOSCompiler(Compiler):
def compile_to_object(self):
print('把swift转化成LIVM二进制代码')
def run(self):
print('运行起来了')
def collect_Source(self):
print('收集swift代码源码')
if __name__ == '__main__':
ios = IOSCompiler()
ios.compile_and_run()
'''结果:
收集swift代码源码
把swift转化成LIVM二进制代码
运行起来了'''
模板方法UML图
实例
一个旅行社的例子:定义各种旅游路线,并提供度假套装行程。一个行程套餐就是客户的一次旅行。旅行还有一些详细信息比如地点等。同样的旅行还可以根据客户需求进行定制。
from abc import ABCMeta, abstractmethod
# 抽象接口,定义不同日期旅行方式和地点等细节
class Trip(metaclass=ABCMeta):
# 抽象方法,由concrete class实现,设置交通方式
@abstractmethod
def set_transport(self):
pass
# 特定日期参观地点
@abstractmethod
def day1(self):
pass
@abstractmethod
def day2(self):
pass
@abstractmethod
def day3(self):
pass
@abstractmethod
def return_home(self):
pass
# 创建完整行程算法
def itinerary(self):
self.set_transport()
self.day1()
self.day2()
self.day3()
self.return_home()
# 接下来两个具体行程继承旅行的抽象方法
class XIANTrip(Trip):
def set_transport(self):
print('飞机去西安')
def day1(self):
print('兵马俑')
def day2(self):
print('华清池')
def day3(self):
print('大明宫')
def return_home(self):
print('回家')
class HangZhouTrip(Trip):
def set_transport(self):
print('飞机去杭州')
def day1(self):
print('西湖')
def day2(self):
print('西湖')
def day3(self):
print('西湖')
def return_home(self):
print('回家')
# 旅行社根据客户选择安排旅行具体实现
class TravelAgency:
def arrange_trip(self):
choice = '西安'
self.trip = XIANTrip()
self.trip.itinerary()
TravelAgency().arrange_trip()
'''
飞机去西安
兵马俑
华清池
大明宫
回家
'''
模板方法的有点和缺点
优点
- 没有代码重复
- 用继承,可以重用代码,只有很少的方法要重写
- 灵活允许子类决定如何实现算法中的步骤
缺点
- 很难对流程调试和理解,最终实现的方法可能是一个没什么用的方法,或者根本没有实现某个抽象方法。所以文档和错误处理必须很严格
- 任何层次变更都会对实现造成干扰,难维护。
一些问题
-
不能禁止底层组件调用更高层组件中的方法,但要注意不能让高层组件和底层组件出现彼此依赖。
-
策略模式和模板模式都是封装算法,模板模式取决于继承,而策略模式取决于组合。模板方法是通过子类在编译时进行算法选择,策略模式是在运行时进行选择。