python设计模式-模板方法模式

栏目: Python · 发布时间: 5年前

内容简介:首先先介绍一下咖啡和茶的冲泡方法:用python代码实现冲泡方法大概是这个样子:仔细看上边两端代码会发现,茶和咖啡的实现方式基本类似,都有

首先先介绍一下咖啡和茶的冲泡方法:

1. 把水煮沸
2. 用沸水浸泡茶叶
3. 把茶放到杯子里
复制代码

咖啡

1. 把水煮沸
2. 用沸水冲泡咖啡
3. 把咖啡倒进杯子
4. 加糖和牛奶
复制代码

python 代码实现冲泡方法大概是这个样子:

# 茶的制作方法
class Tea:

    def prepare_recipe(self):
        # 在下边实现具体步骤
        self.boil_water()
        self.brew_tea_bag()
        self.pour_in_cup()
        
    def boil_water(self):
        print("Boiling water")
        
    def brew_tea_bag(self):
        print("Steeping the tea")
        
    def pour_in_cup(self):
        print("Pouring into cup")
复制代码
# 咖啡的制作方法
class Coffee:

    def prepare_recipe(self):
        # 在下边实现具体步骤
        self.boil_water()
        self.brew_coffee_grinds()
        self.pour_in_cup()
        self.add_sugar_and_milk()
        
    def boil_water(self):
        print("Boiling water")
        
    def brew_coffee_grinds(self):
        print("Dripping Coffee through filter")
        
    def pour_in_cup(self):
        print("Pouring into cup")
        
    def add_sugar_and_milk(self):
        print("Adding Sugar and Milk")
复制代码

仔细看上边两端代码会发现,茶和咖啡的实现方式基本类似,都有 prepare_recipeboil_waterpour_in_cup 这三个方法。

问题: 如何重新设计这两个类来让代码更简洁呢?

首先看一下两个类的类图:

python设计模式-模板方法模式
prepare_recipe() boil_water() pour_in_cup()
prepare_recipe()

现在把 prepare_recipe() boil_water() pour_in_cup() 三个方法抽取出来做成一个父类 CoffeineBeverage()TeaCoffee 都继自 CoffeineBeverage()

python设计模式-模板方法模式

因为每个类中 prepare_recipe() 实现的方法不一样,所以 TeaCoffee 类都分别实现了 prepare_recipe()问题 : 那么,有没有办法将 prepare_recipe() 也抽象化?

对比 TeaCoffeeprepare_recipe() 方法会发现,他们之间的差异主要是:

def prepare_recipe(self):
    # 相同部分隐藏
    # self.boil_water()
    self.brew_tea_bag()  # 差异1
    #self.pour_in_cup()
        
def prepare_recipe(self):
    # 相同部分隐藏
    # self.boil_water()
    self.brew_coffee_grinds() # 差异1
    # self.pour_in_cup()
    self.add_sugar_and_milk() # 差异2

复制代码

这里的实现思路是,将两处差异分别用新的方法名代替,替换后结果如下:

def prepare_recipe(self):
    # 新的实现方法
    self.boil_water()
    self.brew() # 差异1 使用brew 代替 brew_tea_bag 和 brew_coffee_grinds
    self.pour_in_cup()
    self.add_condiments() # 差异2 Tea 不需要此方法,可以用空的实现代替

复制代码

新的类图如下:

python设计模式-模板方法模式

现在,类 TeaCoffee 只需要实现具体的 brew()add_condiments() 方法即可。代码实现如下:

class CoffeineBeverage:

    def prepare_recipe(self):
        # 新的实现方法
        self.boil_water()
        self.brew() 
        self.pour_in_cup()
        self.add_condiments()
        
    def boil_water(self):
        print("Boiling water")
        
    def brew(self):
        # 需要在子类实现
        raise NotImplementedError
        
    def pour_in_cup(self):
        print("Pouring into cup")
        
    def add_condiments(self):
        # 这里其实是个钩子方法,子类可以视情况选择是否覆盖
        # 钩子方法是一个可选方法,也可以让钩子方法作为某些条件触发后的动作
        pass

# 茶的制作方法
class Tea(CoffeineBeverage):
        
    def brew(self):
        # 父类中声明了 raise NotImplementedError,这里必须要实现此方法
        print("Steeping the tea")
        
    # Tea 不需要 add_condiments 方法,所以这里不需要实现

# 咖啡的制作方法
class Coffee(CoffeineBeverage):
        
    def brew(self):
        # 父类中声明了 raise NotImplementedError,这里必须要实现此方法
        print("Dripping Coffee through filter")
        
    def add_condiments(self):
        print("Adding Sugar and Milk")
复制代码

模板方法

上述抽象过程使用的就是模板方法。模板方法定义了一个算法的步骤,并且允许子类为一个或多个步骤提供实现。在这个例子中, prepare_recipe 就是一个模板方法。

定义: 模板方法牧师在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

优点

  1. 使用模板方法可以将代码的复用最大化
  2. 子类只需要实现自己的方法,将算法和实现的耦合降低。

好莱坞原则

模板方法使用到了一个原则, 好莱坞原则

好莱坞原则 ,别调用我,我会调用你。

python设计模式-模板方法模式

在这个原则之下,允许低层组件将自己挂钩到系统上,但是由高层组件来决定什么时候使用这些低层组件。

在上边的例子中,CoffeineBeverage 是高层组件,Coffee和Tea 是低层组件,他们不会之间调用抽象类(CoffeineBeverage)。

一个例子:chestnut:

Python 第三方表单验证包 wtforms 的表单验证部分就使用到了模板方法模式。Field 类中 validate 方法就是一个模板方法,在这个方法中,会调用 pre_validate_run_validation_chainpost_validate 方法来验证表单,这些方法也都可以在子类中重新实现。具体实现可以参考以下源码。

源码地址: github.com/wtforms/wtf…

参考链接

本文例子来自《Head First 设计模式》

最后,感谢女朋友支持和包容,比:heart:

也可以在公号输入以下关键字获取历史文章: 公号&小程序 | 设计模式 | 并发&协程

python设计模式-模板方法模式

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

鼠标宣言

鼠标宣言

约翰·里德尔 / 倪萍、梅清豪 / 上海人民 / 2005-08-01 / 25.00

本书针对信息时代营销者不知该如何满足消费者的营销困境,提出了崭新的解决方案——以新技术为基础的群体筛选和推荐系统。随着信息管理软件和internet的高速发展,群体筛选技术下的推荐系统通过大量有关消费者偏好和购物记录的信息,以及对产品特征的准确把握,能够为消费者进行精确的推荐,提高了消费者的购物效率和准确度以及营销者的营销效率和竞争力。本书通过通俗而到位的讲解,向读者全面介绍了有关群体筛选技术的理......一起来看看 《鼠标宣言》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换