模板方法模式——封装算法

  • 模板方法模式
  • 设计模式
  • UML类图
  • 模板方法实践
  • 钩子
  • 好莱坞原则与模板方法
  • 优缺点


模板方法模式

模板方法模式是一种行为设计模式,通过一种称为模板方法的方式来定义程序框架或算法。模板方法模式还通过将这些步骤中的一些实现推迟到子类来帮助重新定义或定制算法的某些步骤。

按照软件开发术语来说,我们可以使用抽象类类定义算法的步骤,这些步骤在模板方法模式的上下文也称为原始操作。

模板方法模式:

  • 当多个算法或类实现类似或相同的逻辑的时候
  • 在子类中实现算法有助于减少重复代码的时候
  • 可以让子类利用覆盖实现行为来定义多个算法的时候

设计模式

主要意图

  • 使用基本操作定义算法的框架
  • 重新定义子类的某些操作,而无需修改算法的结构
  • 实现代码利用并避免重复工作
  • 利用通用接口或实现

术语

  • AbstractClass:声明一个定义算法步骤的接口
  • ConcreteClass:定义子类特定的步骤
  • template_method():通过调用步骤方法来定义算法

假设IOS设备开发自己的交叉编译器并运行程序

首先开发一个抽象类(编译器)来定义编译器的算法。编译器执行操作是收集有程序语言编写的源代码,然后编译成目标代码。我们将步骤定义为collectSource()和compileToObject()抽象方法,同时还定义了负责执行程序的run()方法。该算法由compileAndRun()方法来定义的,通过内部调用collectSource()、compileToObject()和run()方法来定义编译器的算法。

from abc import ABCMeta, abstractmethod

class Compiler(metaclass = ABCMeta):
    @abstractmethod
    def collectSource(self):
        pass 
    @abstractmethod
    def compileToObject(self):
        pass 
    @abstractmethod
    def run(self):
        pass 
    def 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()
Collecting Swift Source Code
Compiling Swift code to LLVM bitcode
Program runing on runtime environment

UML类图

python django 模板 safe python模板方法_子类


4个主要参与者

  • AbstractClass:抽象方法的帮助下定义算法的操作或步骤。这些步骤将具体子类覆盖
  • template_method():定义算法的框架
  • ConcreteClass:实现步骤,来执行算法子类的特定步骤
from abc import ABCMeta, abstractmethod

class AbstractClass(metaclass = ABCMeta):
    def __init__(self):
        pass 
    @abstractmethod
    def operation1(self):
        pass 
    @abstractmethod
    def operation2(self):
        pass 
    def template_method(self):
        print("Defining the Algorithm . Operation1 follows Operation2")
        self.operation2()
        self.operation1()
class ConcreteClass(AbstractClass):
    def operation1(self):
        print("My Concrete Operation1")
    def operation2(self):
        print("Operation 2 remains same")
class Client:
    def main(self):
        self.concreate = ConcreteClass()
        self.concreate.template_method()

client = Client()
client.main()
Defining the Algorithm . Operation1 follows Operation2
Operation 2 remains same
My Concrete Operation1

模板方法实践

想象一个旅行社的例子:他们定义了各种旅游路线,并提供独家套装行程。

设计注意事项

  • 根据UML图来看,应该创建一个定义旅行的AbstractClass接口
  • 旅行应包含多个抽象方法,定义所使用的交通方式
  • 模板方法itinerary()将实际定义该旅行的行程
  • 定义ConcreteClasses,以帮助我们根据客户的需求对旅行进行相应的定制

抽象类,即Trip

  • 抽象对象由Trip类表示,它是一个接口,定义了不同日子使用的交通方法和参观的地方等细节
  • setTransport是一个抽象方法,由ConcreteClass实现作用格式设置交通方法
  • day1(),day(2),day(3)抽象方法定义了特定日期所参观的地点
  • itinerary()模板方法创建完整的行程

具体类

  • 主要两个实现Trip接口的具体类:VeniceTrip和MaldvesTrip
  • 两个具体类代表游客根据他们的选择和兴趣所进行的两次不同的旅行
  • 都是实现抽象类的函数

游客

  • TravelAgency类代表该示例中的Client对象
  • 根据旅游者的选择,相应的类将被实例化
  • 对象调用itinerary()模板方法,根据客户的选择为游客安排相应的旅行
from abc import abstractmethod, ABCMeta

class Trip(metaclass = ABCMeta):
    @abstractmethod
    def setTransport(self):
        pass 
    @abstractmethod
    def day1(self):
        pass 
    @abstractmethod
    def day2(self):
        pass
    @abstractmethod
    def day3(self):
        pass 
    @abstractmethod
    def returnHome(self):
        pass 
    def itinerary(self):
        self.setTransport()
        self.day1()
        self.day2()
        self.day3()
        self.returnHome()
class VeniceTrip(Trip):
    def setTransport(self):
        print("Take a boat and find your way in Grand Cana1")
    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 snorkelling")
    def day3(self):
        print("Relax on the beach and enjoy the sun")
    def returnHome(self):
        print("Don't fell like leaving th beach...")
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()
What kind of place you'd like to go historical or to a beach?beach
On foot, on any island, Wow!
Enjoy the marine life of Banana Reef
Go for the water sports and snorkelling
Relax on the beach and enjoy the sun
Don't fell like leaving th beach...

钩子

钩子是在抽象类中声明的方法,通常被赋予一个默认实现。钩子的背后的思想是为子类提供按需钩取算法的能力。

好莱坞原则与模板方法

好莱坞原则是一种设计原则。即不要给我们打电话,我会给打给你。

允许底层组件使用好莱坞原则将自己挂入系统,高层组件确定底层系统的使用方式。

优缺点

  • 没有代码重复
  • 模板方法模式使用继承而不是合成,因此能够对代码进行重用。
  • 灵活性允许子类决定如何实现算法中步骤。

缺点:

  • 调试和理解模板方法模式中的流程序列有时会令人困惑。
  • 模板框架维护可能是一个问题