精通Python设计模式第二版 第 2 章 建造者模式 学习笔记

建造者模式

假设我们要创建一个由对各部分组成的独享,而且创建过程需要一步一步地完成。只有创建了所有的部分,该对象才是完成的。这种需求可以使用建造者模式帮助我们。建造者模式将复杂对象的构建与其表示分离。通过将构建与表示分离,相同的构建可用于创建几个不同的表示

假设我们想创建一个HTML页面生成器。HTML页面的基础结构(构建部分)大同小异:以<html>开始,以</html>结束,在HTML部分中有<head></head>元素,在head部分中有<title>和</title>原色,以此类推。但是页面的表示可能不同。每个页面都有自己的标题、头部和不同的<body>内容。此外,页面通常按步骤构建:一个函数添加标题,一个函数添加主头部,一个函数添加脚注,等等。只有在页面的整个结构完成之后,才能使用一个最终的渲染函数将其呈现给客户端。我们可以进一步拓展HTML生成器,使其能够生成完全不同的HTML页面。一个页面可能包含表格,一个可能包含图像库,一个页面可能包含联系人表单,等等

两个参与者

  • 建造者(builder):负责创建复杂独享的各个部分的组件。
  • 指挥者(director):使用建造者实例控制构建过程的组件。

定制个人计算机问题

假设我们想买一台新计算机,计算机的配置我们自己挑选。我们可以使用建造者模式解决这个问题,在这个方案里,我们就是指挥者,向制造商(builder)发出指令

1. 定义Computer类

class Computer():"""Computer :Attributes:"""def __init__(self, serial_number):self.serial = serial_numberself.memory = None  # 单位为GBself.hdd = None  # 单位为GBself.gpu = Nonedef __str__(self):info = (f'Memory: {self.memory}GB',f'Hard Disk: {self.hdd}GB',f'Graphics Card: {self.gpu}')return '\n'.join(info)

2. 定义ComputerBuilder类

class Computer():"""Computer :Attributes:"""def __init__(self, serial_number):self.serial = serial_numberself.memory = None  # 单位为GBself.hdd = None  # 单位为GBself.gpu = Nonedef __str__(self):info = (f'Memory: {self.memory}GB',f'Hard Disk: {self.hdd}GB',f'Graphics Card: {self.gpu}')return '\n'.join(info)

3. 定义HardwareEngineer类

class HardwareEngineer():"""HardwareEngineer :Attributes:"""def __init__(self):self.builder = Nonedef construct_computer(self, memory, hdd, gpu):self.builder = ComputerBuilder()(self.builder.configure_memory(memory),self.builder.configure_hdd(hdd),self.builder.configure_gpu(gpu))@propertydef computer(self):return self.builder.computer

4. 以main()函数结束,并从命令行调用方法

def main():engineer = HardwareEngineer()engineer.construct_computer(hdd=500,memory=8,gpu='GeForce GTX 650 Ti')computer = engineer.computerprint(computer)if __name__ == '__main__':main()

获得打印如下

Memory: 8GB
Hard Disk: 500GB
Graphics Card: GeForce GTX 650 Ti

完整代码如下


class Computer():"""Computer :Attributes:"""def __init__(self, serial_number):self.serial = serial_numberself.memory = None  # 单位为GBself.hdd = None  # 单位为GBself.gpu = Nonedef __str__(self):info = (f'Memory: {self.memory}GB',f'Hard Disk: {self.hdd}GB',f'Graphics Card: {self.gpu}')return '\n'.join(info)class ComputerBuilder():"""ComputerBuilder :Attributes:"""def __init__(self):self.computer = Computer('AG23385193')def configure_memory(self, amount):self.computer.memory = amountdef configure_hdd(self, amount):self.computer.hdd = amountdef configure_gpu(self, gpu_model):self.computer.gpu = gpu_modelclass HardwareEngineer():"""HardwareEngineer :Attributes:"""def __init__(self):self.builder = Nonedef construct_computer(self, memory, hdd, gpu):self.builder = ComputerBuilder()(self.builder.configure_memory(memory),self.builder.configure_hdd(hdd),self.builder.configure_gpu(gpu))@propertydef computer(self):return self.builder.computerdef main():engineer = HardwareEngineer()engineer.construct_computer(hdd=500,memory=8,gpu='GeForce GTX 650 Ti')computer = engineer.computerprint(computer)if __name__ == '__main__':main()

这个方案中,我们引入了建造者CompuerBuilder、指挥者HardwareEngineer,并逐步构建了一台计算机,它现在支持不同的配置memory,hdd,gpu

定制披萨问题

现在让我们看看如果使用建造者设计模式来制作比萨订购程序。披萨的例子特别又去,因为披萨的制作不走应该遵循特定的顺序。加调味汁之前,首先要准备面团。加配料之前,首先要加调味汁。只有调味汁和配料都放在面团上后,你才能开始烤披萨。此外,每个披萨通常需要不同的烘烤时间,这取决于面团的厚度和所用的配料

1. 声明一些Enum

使用这些枚举来记录制作披萨的状态以及披萨的一些相关属性

from enum import Enum
import timePizzaProgress = Enum('PizzaProgress', 'queued preparation baking ready')
PizzaDough = Enum('PizzaDough', 'thin thick')
PizzaSauce = Enum('PizzaSauce', 'tomato creme_fraiche')
PizzaTopping = Enum('PizzaTopping', 'mozzarella double_mozzarella bacon ham mushrooms red_onion oregano')STEP_DELAY = 3  # 单位为秒

2. 定义Pizza类

class Pizza():"""Pizza :Attributes:"""def __init__(self, name):self.name = nameself.dough = Noneself.sauce = Noneself.topping = []def __str__(self):return self.namedef prepare_dough(self, dough):self.dough = doughprint(f'preparing the {self.dough.name} dough of your {self}...')time.sleep(STEP_DELAY)print(f'done with the {self.dough.name} dough')

3. 定义Builder类

有两个建造者:一个用于创建玛格丽特披萨,另一个用于创建奶油培根披萨。每个建造者创建一个Pizza实例,并包含遵循比萨制作过程的方法:prepare_dough()、add_sauce() 等。

class MargaritaBuilder():"""MargaritaBuilder :Attributes:"""def __init__(self):self.pizza = Pizza('margarita')self.progress = PizzaProgress.queuedself.baking_time = 5  # 单位为秒,仅做示例使用def prepare_dough(self):self.progress = PizzaProgress.preparationself.pizza.prepare_dough(PizzaDough.thin)def add_sauce(self):print('adding the tomato sauce to your margarita')self.pizza.sauce = PizzaSauce.tomatotime.sleep(STEP_DELAY)print('done with the tomato sauce')def add_topping(self):topping_desc = 'double mozzarella, oregano'topping_items = (PizzaTopping.double_mozzarella, PizzaTopping.oregano)print(f'adding the topping ({topping_desc}) to your margarita')self.pizza.topping.append([t for t in topping_items])time.sleep(STEP_DELAY)print(f'done with the topping ({topping_desc})')def bake(self):self.progress = PizzaProgress.bakingprint(f'baking your margarita for {self.baking_time} seconds')time.sleep(self.baking_time)self.progress = PizzaProgress.readyprint('your margarita is ready')class CreamyBaconBuilder():"""CreamyBaconBuilder :Attributes:"""def __int__(self):self.pizza = Pizza('creamy bacon')self.progress = PizzaProgress.queuedself.baking_time = 7  # 单位为秒def prepare_dough(self):self.progress = PizzaProgress.preparationself.pizza.prepare_dough(PizzaDough.thick)def add_sauce(self):print('adding the creme fraiche sauce to your creamy bacon')self.pizza.sauce = PizzaSauce.creme_fraichetime.sleep(STEP_DELAY)print('done with the creme fraiche sauce')def add_topping(self):topping_desc = 'mozzarella, bacon, ham, mushrooms, red onion, oregano'topping_items = (PizzaTopping.mozzarella,PizzaTopping.bacon,PizzaTopping.ham,PizzaTopping.mushrooms,PizzaTopping.red_onion,PizzaTopping.oregano)print(f'adding the topping ({topping_desc}) to your creamy bacon')self.pizza.topping.append([t for t in topping_items])time.sleep(STEP_DELAY)print(f'done with the topping ({topping_desc})')def bake(self):self.progress = PizzaProgress.bakingprint(f'baking your creamy bacon for {self.baking_time} seconds')time.sleep(self.baking_time)self.progress = PizzaProgress.readyprint('your creamy bacon is ready')

4. 定义Waiter类

在这个例子中 指挥者是服务员。Waiter类的核心是construct_pizza()方法,它接收一个建造者作为参数,并以正确的顺序执行所有比萨准备。

class Waiter():"""Waiter :Attributes:"""def __init__(self):self.builder = Nonedef construct_pizza(self, builder):self.builder = buildersteps = (builder.prepare_dough,builder.add_sauce,builder.add_topping,builder.bake)[step() for step in steps]@propertydef pizza(self):return self.builder.pizza

5. 处理订单需求

validate_style() 确保用户提供有效的输入

def validate_style(builders):try:input_msg = 'What pizza would you like, [m]argarita or [c]reamy bacon? \n'pizza_style = input(input_msg)builder = builders[pizza_style]()valid_input = Trueexcept KeyError:error_msg = 'Sorry, only margarita (key m) and creamy bacon (key c) are available'print(error_msg)return (False, None)return (True, builder)def main():builders = dict(m=MargaritaBuilder, c=CreamyBaconBuilder)valid_input = Falsewhile not valid_input:valid_input, builder = validate_style(builders)print()waiter = Waiter()waiter.construct_pizza(builder)pizza = waiter.pizzaprint()print(f'Enjoy your {pizza}!')if __name__ == '__main__':main()

获得打印如下

What pizza would you like, [m]argarita or [c]reamy bacon?
mpreparing the thin dough of your margarita...
done with the thin dough
adding the tomato sauce to your margarita
done with the tomato sauce
adding the topping (double mozzarella, oregano) to your margarita
done with the topping (double mozzarella, oregano)
baking your margarita for 5 seconds
your margarita is readyEnjoy your margarita!

完整代码如下


from enum import Enum
import timePizzaProgress = Enum('PizzaProgress', 'queued preparation baking ready')
PizzaDough = Enum('PizzaDough', 'thin thick')
PizzaSauce = Enum('PizzaSauce', 'tomato creme_fraiche')
PizzaTopping = Enum('PizzaTopping', 'mozzarella double_mozzarella bacon ham mushrooms red_onion oregano')STEP_DELAY = 3  # 单位为秒class Pizza():"""Pizza :Attributes:"""def __init__(self, name):self.name = nameself.dough = Noneself.sauce = Noneself.topping = []def __str__(self):return self.namedef prepare_dough(self, dough):self.dough = doughprint(f'preparing the {self.dough.name} dough of your {self}...')time.sleep(STEP_DELAY)print(f'done with the {self.dough.name} dough')class MargaritaBuilder():"""MargaritaBuilder :Attributes:"""def __init__(self):self.pizza = Pizza('margarita')self.progress = PizzaProgress.queuedself.baking_time = 5  # 单位为秒,仅做示例使用def prepare_dough(self):self.progress = PizzaProgress.preparationself.pizza.prepare_dough(PizzaDough.thin)def add_sauce(self):print('adding the tomato sauce to your margarita')self.pizza.sauce = PizzaSauce.tomatotime.sleep(STEP_DELAY)print('done with the tomato sauce')def add_topping(self):topping_desc = 'double mozzarella, oregano'topping_items = (PizzaTopping.double_mozzarella, PizzaTopping.oregano)print(f'adding the topping ({topping_desc}) to your margarita')self.pizza.topping.append([t for t in topping_items])time.sleep(STEP_DELAY)print(f'done with the topping ({topping_desc})')def bake(self):self.progress = PizzaProgress.bakingprint(f'baking your margarita for {self.baking_time} seconds')time.sleep(self.baking_time)self.progress = PizzaProgress.readyprint('your margarita is ready')class CreamyBaconBuilder():"""CreamyBaconBuilder :Attributes:"""def __int__(self):self.pizza = Pizza('creamy bacon')self.progress = PizzaProgress.queuedself.baking_time = 7  # 单位为秒def prepare_dough(self):self.progress = PizzaProgress.preparationself.pizza.prepare_dough(PizzaDough.thick)def add_sauce(self):print('adding the creme fraiche sauce to your creamy bacon')self.pizza.sauce = PizzaSauce.creme_fraichetime.sleep(STEP_DELAY)print('done with the creme fraiche sauce')def add_topping(self):topping_desc = 'mozzarella, bacon, ham, mushrooms, red onion, oregano'topping_items = (PizzaTopping.mozzarella,PizzaTopping.bacon,PizzaTopping.ham,PizzaTopping.mushrooms,PizzaTopping.red_onion,PizzaTopping.oregano)print(f'adding the topping ({topping_desc}) to your creamy bacon')self.pizza.topping.append([t for t in topping_items])time.sleep(STEP_DELAY)print(f'done with the topping ({topping_desc})')def bake(self):self.progress = PizzaProgress.bakingprint(f'baking your creamy bacon for {self.baking_time} seconds')time.sleep(self.baking_time)self.progress = PizzaProgress.readyprint('your creamy bacon is ready')class Waiter():"""Waiter :Attributes:"""def __init__(self):self.builder = Nonedef construct_pizza(self, builder):self.builder = buildersteps = (builder.prepare_dough,builder.add_sauce,builder.add_topping,builder.bake)[step() for step in steps]@propertydef pizza(self):return self.builder.pizzadef validate_style(builders):try:input_msg = 'What pizza would you like, [m]argarita or [c]reamy bacon? \n'pizza_style = input(input_msg)builder = builders[pizza_style]()valid_input = Trueexcept KeyError:error_msg = 'Sorry, only margarita (key m) and creamy bacon (key c) are available'print(error_msg)return (False, None)return (True, builder)def main():builders = dict(m=MargaritaBuilder, c=CreamyBaconBuilder)valid_input = Falsewhile not valid_input:valid_input, builder = validate_style(builders)print()waiter = Waiter()waiter.construct_pizza(builder)pizza = waiter.pizzaprint()print(f'Enjoy your {pizza}!')if __name__ == '__main__':main()

流畅创建者

简略版建造者模型 解决披萨订单问题


class Pizza():"""Pizza :Attributes:"""def __init__(self,builder):self.garlic = builder.garlicself.extra_cheese = builder.extra_cheesedef __str__(self):garlic = 'yes' if self.garlic else 'no'cheese = 'yes' if self.extra_cheese else 'no'info = (f'Garlic: {garlic}',f'Extra cheese: {cheese}')return '\n'.join(info)class PizzaBuilder():"""PizzaBuilder :Attributes:"""def __init__(self):self.extra_cheese = Falseself.garlic = Falsedef add_garlic(self):self.garlic = Truereturn selfdef add_cheese(self):self.extra_cheese = Truereturn selfdef build(self):return Pizza(self)if __name__ == '__main__':pizza = Pizza.PizzaBuilder().add_cheese().add_garlic().build()print(pizza)

获得打印如下

Garlic: yes
Extra cheese: yes

Python 设计模式 - 建造者模式相关推荐

  1. Python设计模式-建造者模式

    Python设计模式-建造者模式 代码基于3.5.2,代码如下; #coding:utf-8 #建造者模式 class Burger():name = ""price = 0.0d ...

  2. Python设计模式-状态模式

    Python设计模式-状态模式 代码基于3.5.2,代码如下; #coding:utf-8 #状态模式class state():def writeProgram(self,work):raise N ...

  3. Python设计模式-备忘录模式

    Python设计模式-备忘录模式 代码基于3.5.2,代码如下; #coding:utf-8 #备忘录模式 import randomclass gameCharacter():vitality = ...

  4. Python设计模式-解释器模式

    Python设计模式-解释器模式 代码基于3.5.2,代码如下; #coding:utf-8 #解释器模式class PlayContext():play_text = Noneclass Expre ...

  5. Python设计模式-命令模式

    Python设计模式-命令模式 代码基于3.5.2,代码如下; #coding:utf-8 #命令模式class barbecuer():def bakeButton(self):print(&quo ...

  6. Python设计模式-策略模式

    Python设计模式-策略模式 代码基于3.5.2,代码如下; #coding:utf-8 #策略模式class sendInterface():def send(self,value):raise ...

  7. Python设计模式-外观模式

    Python设计模式-外观模式 代码基于3.5.2,代码如下; #coding:utf-8 # 外观模式class AlarmSensor:def run(self):print("Alar ...

  8. Python设计模式-桥接模式

    Python设计模式-桥接模式 基于Python3.5.2,代码如下 #coding:utf-8class Shape():name = ""param = "" ...

  9. Python设计模式-代理模式

    Python设计模式-代理模式 基于Python3.5.2,代码如下 #coding:utf-8info_struct = dict() info_struct["addr"] = ...

最新文章

  1. laravel 处理excel插件maatwebsite/excel
  2. numpy np.sum()函数(求给定轴上的数组元素的总和)(与ndarray.sum()函数等价)
  3. 四元数和欧拉角的相互转换
  4. 远程阿里云window服务器报错身份验证错误
  5. harbor安装_Harbor简单安装部署,镜像仓库存储使用阿里云OSS
  6. probe request帧结构_WIFI基础知识(802.11)
  7. matlab波纹噪声图像的平滑,matlab图像水波纹
  8. [Perl系列—] 1. 清空目录及目录中的所有文件
  9. 树形$dp$学习笔记
  10. 【电子电路】电子基础基本知识和面试要点
  11. 【Spark】Spark的机器学习算法库——Spark MLilb
  12. 基于微信小程序的疫情智慧社区管理系统 计算机毕业设计 后台管理系统
  13. Gist in GitHub
  14. linux发出声音的命令,在Linux中发出哔哔声C
  15. 毛球科技点评区块链在组织和商业生态系统中的未来
  16. 半导体器件相关专业词汇积累ing
  17. 为何买了专业设备又要卖掉?怎样正确自学拍摄、剪辑做视频?
  18. 张一鸣:不甘平庸的年轻人 全都有同一个特质
  19. 2、PVID(本征VLAN)实验配置步骤
  20. 陈皓的C语言系列文章合集

热门文章

  1. 比较全的Struts介绍04
  2. FreeSwitch_CallCenter_Tiers
  3. 泰禾智能:智能改变未来,成就工业设备行业佼佼者
  4. 我的-Android-面试故事---13家面试记录,附面试答案,android星座查询源码
  5. 解决旧笔记本电脑的ME固件的驱动安装程序不支持WIN10安装的方法
  6. Docker基础笔记
  7. Toefl-Speaking
  8. 使用 git tag 给项目打标签
  9. postgresql模糊查询不区分大小写
  10. 45句绝美宋词,哪一句触动了你?