资讯专栏INFORMATION COLUMN

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

jzzlee / 3320人阅读

摘要:问题如何重新设计这两个类来让代码更简洁呢首先看一下两个类的类图每个类中都有方法。模板方法定义了一个算法的步骤,并且允许子类为一个或多个步骤提供实现。好莱坞原则模板方法使用到了一个原则,好莱坞原则。


date: 2018-12-02T17:23:56+08:00
description: python 设计模式 模板方法模式
draft: false
slug: "python-design-pattern-template-pattern"
categories: ["development", "python", "设计模式"]
tags: ["python", "读书笔记", "设计模式"]

title: "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 这三个方法。

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

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

每个类中都有 prepare_recipe() boil_water() pour_in_cup()方法。

每个类中prepare_recipe()方法的实现都不一样。

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

因为每个类中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 不需要此方法,可以用空的实现代替

新的类图如下:

现在,类 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 就是一个模板方法。

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

使用模板方法可以将代码的复用最大化

子类只需要实现自己的方法,将算法和实现的耦合降低。

好莱坞原则

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

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


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

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

一个例子

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/42730.html

相关文章

  • django官方文档1.11编翻:1-1-1概述

    摘要:您的应用程序的目录,它包含模式和回调函数之间的简单映射。更性感自动生成的管理功能这个概述几乎没有触及表面。 django概述 因为django是在快节奏的编辑环境下开发的,它旨在使常见的Web开发任务变得快速而简单。 这是一个关于如何用django编写数据库驱动的Web应用程序的非正式概述。 本文档的目的是为您提供足够的技术细节来了解django的工作原理,但这不是一个教程或参考 - ...

    阿罗 评论0 收藏0
  • python设计模式

    摘要:在本节实验中,我们学习了四种设计模式策略模式,观察者模式,命令模式以及模板方法模式。这四种设计模式都是行为型模式。这就是适配器模式。下面让我们看看适配器模式在实验楼中使用吧。准确来说,装饰者模式能动态的给对象添加行为。 1、策略模式 策略模式将各种操作(算法)进行封装,并使它们之间可以互换。互换的意思是说可以动态改变对象的操作方式(算法)。 -- coding: utf-8 -- im...

    array_huang 评论0 收藏0
  • 基于Linux环境的Web.py框架介绍

    摘要:前言在文章基于环境搭建框架方法介绍中介绍了客户端和服务器的交互过程,服务器接收客户端的请求后,由应用服务器对浏览器的请求进行处理,将生成的响应传递给服务器,再由服务器返回给客户端。 前言 在文章《基于Linux环境搭建Nginx+uWSGI+Python框架方法介绍》中介绍了客户端和Web服务器的交互过程,Web服务器接收客户端的请求后,由Web应用服务器对浏览器的请求进行处理,将生成...

    caikeal 评论0 收藏0
  • Lunar, 一个Python网络框架的实现

    摘要:核心的几个组件模板引擎,框架,请求和应答的处理还是有一些难度,但是经过一步步的分析和编码还是能够完成功能。模板引擎模板引擎是另外一个比较大和的模块。 前前后后,大概两个月的时间,lunar这个项目终于达到了一个很高的完整度。 Lunar是一个Python语言的网络框架,类似于Django,Flask,Tornado等当下流行的web framework。最初有这个想法是在大二下学期,...

    邱勇 评论0 收藏0
  • flask文档学习笔记1-快速入门

    摘要:示例如下静态路由使用动态变量的路由未指定变量类型使用动态变量的路由指定变量类型指定的路由变量,可以作为被装饰的函数参数传入进来。 开始决定认真的在网上写一些东西,主要原因还是在于希望能提升学习效果。虽说python写了有几年,但是web后端框架的确没怎么接触过,买了本狗书寥寥草草的过了一遍,发现很多东西还是理解不深,真的是好记性不如烂笔头,知识也要从基础开始,退回来好好看看官方文档,再...

    lingdududu 评论0 收藏0

发表评论

0条评论

jzzlee

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<