【设计模式】 模板方法模式

前言

1. 单例模式(Singleton Pattern):保证一个类只有一个实例,并提供一个全局的访问点。

2. 工厂模式(Factory Pattern):定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。

3. 观察者模式(Observer Pattern):定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会被自动通知并更新。

4. 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,而不会影响到其他对象。

5. 策略模式(Strategy Pattern):定义一系列的算法,将每个算法封装起来,并使它们可以相互替换。

6. 命令模式(Command Pattern):将请求封装成一个对象,从而使用户可以用不同的请求对客户进行参数化。

7. 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类能够一起工作。

8. 外观模式(Facade Pattern):为子系统中的一组接口提供一个统一的接口,从而使得子系统更加容易使用。

9. 状态模式(State Pattern):允许一个对象在其内部状态改变时改变其行为。

10. 模板方法模式(Template Method Pattern):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中实现。

这些是Python中常用的设计模式,通过使用这些设计模式可以提高代码的可读性、可维护性和重用性。

模板方法模式

模板方法模式是一种行为设计模式,它定义一个算法的骨架,而将一些步骤延迟到子类中。这种模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

组成成分

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下。
    • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
    • 基本方法:是整个算法中的一个步骤,包含以下几种类型。
      • 抽象方法:在抽象类中申明,由具体子类实现。
      • 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法,它们是一个顶级逻辑的一个组成步骤。

具体实例一

制作饮料的模板

from abc import ABC, abstractmethod

# 模板方法模式的抽象类
class BeverageTemplate(ABC):
    # 模板方法定义了算法的骨架
    def prepare_beverage(self):
        self.boil_water()
        self.brew()
        self.pour_in_cup()
        self.add_condiments()

    # 具体步骤由子类实现
    @abstractmethod
    def brew(self):
        pass

    @abstractmethod
    def add_condiments(self):
        pass

    # 公共步骤
    def boil_water(self):
        print("Boiling water")

    def pour_in_cup(self):
        print("Pouring into cup")

# 具体子类实现
class Coffee(BeverageTemplate):
    def brew(self):
        print("Brewing coffee grounds")

    def add_condiments(self):
        print("Adding sugar and milk")

class Tea(BeverageTemplate):
    def brew(self):
        print("Steeping the tea")

    def add_condiments(self):
        print("Adding lemon")

# 客户端代码
if __name__ == "__main__":
    print("Making Coffee:")
    coffee = Coffee()
    coffee.prepare_beverage()

    print("\nMaking Tea:")
    tea = Tea()
    tea.prepare_beverage()

 BeverageTemplate是抽象类,定义了制作饮料的模板方法 prepare_beverage 和一些具体的步骤,如煮水和倒入杯中。CoffeeTea 是具体的子类,分别实现了 brewadd_condiments 方法,定义了各自的饮料制作步骤。

 具体实例二

 出国留学手续设计程序

 流程:索取学校资料提出入学申请办理因私出国护照出境卡和公证申请签证体检订机票准备行装抵达目标学校

  • 通用流程实现在父类

  1. 办理因私出国护照、出境卡和公证
  2. 申请签证
  3. 体检、订机票、准备行装
class StudyAbroad():
    def procedure(self):
        self.LookingForSchool() # 索取学校资料
        self.ApplyForEnrol()  # 入学申请
        self.ApplyForPassport()  # 办理因私出国护照、出境卡和公证
        self.ApplyForVisa()  # 申请签证
        self.ReadyGoAbroad()  # 体检、订机票、准备行装
        self.Arriving()  # 抵达
​
    def LookingForSchool(self):
        '''索取学校资料'''
        raise ValueError('LookingForSchool方法未实现')
​
    def ApplyForEnrol(self):
        '''入学申请'''
        raise ValueError('ApplyForEnrol方法未实现')
​
    def ApplyForPassport(self):
        '''办理因私出国护照、出境卡和公证'''
        print('三.办理因私出国护照、出境卡和公证:')
        print('  1)持录取通知书、本人户口簿或身份证向户口所在地公安机关申请办理因私出国护照和出境卡。')
        print('  2)办理出生公证书,学历、学位和成绩公证,经历证书,亲属关系公证,经济担保公证。')
​
    def ApplyForVisa(self):
        '''申请签证'''
        print('四.申请签证:')
        print('  1)准备申请国外境签证所需的各种资料,包括个人学历、成绩单、工作经历的证明;个人及家庭收入、资金和财产证明;家庭成员的关系证明等;')
        print('  2)向拟留学国家驻华使(领)馆申请入境签证。申请时需按要求填写有关表格,递交必需的证明材料,缴纳签证。有的国家(比如美国、英国、加拿大等)在申请签证时会要求申请人前往使(领)馆进行面试。')
​
    def ReadyGoAbroad(self):
        '''体检、订机票、准备行装'''
        print('五.体检、订机票、准备行装:')
        print('  1)进行身体检查、免疫检查和接种传染病疫苗;')
        print('  2)确定机票时间、航班和转机地点。')
​
    def Arriving(self):
        '''抵达'''
        raise ValueError('Arriving方法未实现')
  • 不通用流程是现在具体的子类 
  1. 索取学校资料
  2. 入学申请
  3. 抵达
class StudyInAmerica(StudyAbroad):
    def LookingForSchool(self):
        '''索取学校资料'''
        print('一.索取学校以下资料:')
        print('  1)对留学意向国家的政治、经济、文化背景和教育体制、学术水平进行较为全面的了解;')
        print('  2)全面了解和掌握国外学校的情况,包括历史、学费、学制、专业、师资配备、教学设施、学术地位、学生人数等;')
        print('  3)了解该学校的住宿、交通、医疗保险情况如何;')
​
    def ApplyForEnrol(self):
        '''入学申请'''
        print('二.入学申请:')
        print('  1)填写报名表;')
        print('  2)将报名表、个人学历证明、最近的学习成绩单、推荐信、个人简历、托福或雅思语言考试成绩单等资料寄往所申请的学校;')
​
    def Arriving(self):
        '''抵达'''
        print('六.抵达目标学校:')
        print('  1)安排住宿;')
        print('  2)了解校园及周边环境。')

调用方法

if __name__ == '__main__':
    xiaoming = StudyInAmerica()
    xiaoming.procedure()

优点

  1. 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
  2. 它在父类中提取了公共的部分代码,便于代码复用。
  3. 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

缺点

  1. 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
  2. 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。

 

容易混淆的概念

模板设计模式和继承的区别

模板设计模式和继承是两种不同的面向对象编程范式。

模板设计模式是一种行为型设计模式,它定义了一个操作的步骤,允许子类为一个或多个步骤提供不同的实现。这种模式允许在不改变操作的结构的情况下重定义某些步骤的实现

而继承则是一种结构性设计模式,它允许将父类的方法、属性等“继承”到子类中,使得子类可以共享父类的方法和属性。这种模式可以用来构建一系列相关的类,并在不改变每个类的行为的情况下扩展他们的功能。

总之,模板设计模式和继承的区别在于前者更强调子类可以在父类的基础上重新定义部分行为,而后者则更强调子类继承父类的行为

用通俗的话来讲,模板方法模式,在父类中已经定义好了一个流程,流程有很多步骤组成,这个步骤是固定的,不能更改,但有些步骤对所有情况都适用,所以抽出来放在父类中实现;而具体情况具体对待的步骤则要通过不同的子类来各自实现。

应用场景

  1. 框架搭建: 在软件框架中,模板方法模式经常被用于定义框架的基本骨架,而留下一些具体实现的细节给子类。这样,框架的使用者可以通过继承和实现具体步骤来扩展和定制框架的行为。

  2. 库和框架中的回调: 在回调机制中,模板方法模式也很有用。例如,GUI库中的事件处理,库提供一个通用的事件处理框架,而用户通过实现特定的事件处理方法来定义自己的行为。

  3. 算法实现: 当一系列算法有着相似的步骤,但具体实现有所不同时,模板方法模式非常有用。例如,排序算法中,排序的框架可以在父类中定义,而具体的比较和交换步骤则由子类实现。

  4. 生命周期管理: 在对象的生命周期管理中,模板方法模式可以用于定义对象的创建、销毁等步骤,而将具体的实现交给子类。

  5. 流程控制: 在业务流程中,如果有一系列的步骤需要按照一定的顺序执行,但某些步骤的实现可能因情况而异,模板方法模式也是一个合适的选择。

参考链接

《大话设计模式》——模板方法模式(Python版) - 知乎

模板设计模式和继承有啥区别-掘金

你可能感兴趣的:(python,设计模式,模板方法模式)