建造者模式(Builder Pattern)
定义
Separate the construction of a complex object from its representation so that the same construction process can create different representations.(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)
《设计模式之禅》
UML 示例
以创建不同口味 pizza 的过程为例,Margarita Pizza 和 CreamyBacon Pizza,而 Waiter 作为一个 Director, Pizza 是最终实现出来的产品。
@startuml
Interface Builder
class MargaritaBuilder
class CreamyBaconBuilder
class Pizza
note left: 每个builder会创建自己的Pizza样式,而Pizza定义的内容很少
class Waiter
note left: waiter负责按照一定的执行顺序依次执行具体的builder中的步骤,产生一个pizza
Waiter #-- Builder
Builder <|-- MargaritaBuilder
Builder <|-- CreamyBaconBuilder
MargaritaBuilder ..> Pizza
CreamyBaconBuilder ..> Pizza
@enduml
代码实现
代码样例来自《精通 python 设计模式》
# coding: utf-8
from enum import Enum
import time
# 定义执行过程和Pizza口味的打印信息
PizzaProgress = 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,包含几个部分dough、sauce、topping
def __init__(self, name):
self.name = name
self.dough = None
self.sauce = None
self.topping = []
def __str__(self):
return self.name
# 此段代码也可以在builder中实现,目的是为了展示不仅仅是可以定义Pizza属性,也可以定义一些方法,
# 来让builder调用
def prepare_dough(self, dough):
self.dough = dough
print('preparing the {} dough of your {}...'.format(self.dough.name, self))
time.sleep(STEP_DELAY)
print('done with the {} dough'.format(self.dough.name))
class MargaritaBuilder:
def __init__(self):
# builder类创建的margatita pizza对象
# 此处能够表现出产品的创建由builder类创建
self.pizza = Pizza('margarita')
self.progress = PizzaProgress.queued
self.baking_time = 5 # 考虑是示例,单位为秒
# 如下的过程都是builder类抽象出的统一接口,所有的builder都有这些接口,由于python与java不同,可以不用提前定义抽象类来继承
def prepare_dough(self):
self.progress = PizzaProgress.preparation
self.pizza.prepare_dough(PizzaDough.thin)
def add_sauce(self):
print('adding the tomato sauce to your margarita...')
self.pizza.sauce = PizzaSauce.tomato
time.sleep(STEP_DELAY)
print('done with the tomato sauce')
def add_topping(self):
print('adding the topping (double mozzarella, oregano) to your margarita')
# 此处实在topping的0位置添加了一个[]list
self.pizza.topping.append([i for i in
(PizzaTopping.double_mozzarella, PizzaTopping.oregano)])
time.sleep(STEP_DELAY)
print('done with the topping (double mozzarrella, oregano)')
def bake(self):
self.progress = PizzaProgress.baking
print('baking your margarita for {} seconds'.format(self.baking_time))
time.sleep(self.baking_time)
self.progress = PizzaProgress.ready
print('your margarita is ready')
class CreamyBaconBuilder:
def __init__(self):
self.pizza = Pizza('creamy bacon')
self.progress = PizzaProgress.queued
self.baking_time = 7 # 考虑是示例,单位为秒
def prepare_dough(self):
self.progress = PizzaProgress.preparation
self.pizza.prepare_dough(PizzaDough.thick)
def add_sauce(self):
print('adding the crème fraîche sauce to your creamy bacon')
self.pizza.sauce = PizzaSauce.creme_fraiche
time.sleep(STEP_DELAY)
print('done with the crème fraîche sauce')
def add_topping(self):
print('adding the topping (mozzarella, bacon, ham, mushrooms, red onion, oregano) to your creamy bacon')
self.pizza.topping.append([t for t in
(PizzaTopping.mozzarella, PizzaTopping.bacon,
PizzaTopping.ham, PizzaTopping.mushrooms,
PizzaTopping.red_onion, PizzaTopping.oregano)])
time.sleep(STEP_DELAY)
print('done with the topping (mozzarella, bacon, ham, mushrooms, red onion, oregano)')
def bake(self):
self.progress = PizzaProgress.baking
print('baking your creamy bacon for {} seconds'.format(self.baking_time))
time.sleep(self.baking_time)
self.progress = PizzaProgress.ready
print('your creamy bacon is ready')
# waiter作为一个director定义了执行过程
class Waiter:
def __init__(self):
self.builder = None
def construct_pizza(self, builder):
self.builder = builder
# step by step一步一步的执行pizza的制作过程
[step() for step in (builder.prepare_dough,
builder.add_sauce, builder.add_topping, builder.bake)]
@property
def pizza(self):
return self.builder.pizza
def validate_style(builders):
try:
pizza_style = input('What pizza would you like, [m]argarita or [c]reamy bacon? ')
builder = builders[pizza_style]() # 根据用户输入产生builder
valid_input = True
except KeyError as err:
print('Sorry, only margarita (key m) and creamy bacon (key c) are available')
return (False, None)
return (True, builder)
def main():
builders = dict(m=MargaritaBuilder, c=CreamyBaconBuilder)
valid_input = False
while not valid_input:
valid_input, builder = validate_style(builders)
print()
waiter = Waiter()
waiter.construct_pizza(builder)
pizza = waiter.pizza
print()
print('Enjoy your {}!'.format(pizza))
if __name__ == '__main__':
main()
应用场景
- 建造者模式个人理解是客户化,定制化装配过程的时候需要使用到的。
- 建造者模式与工厂模式的区别就在于工厂模式的产品是固定规格的,写死的,非定制化的。就好比是自己买的品牌型号固定的电脑,还是自己组装一台电脑一样。前者是所有参数固定了,而后者参数由客户自己决定。
- 怎样理解将构建与表示分离? 构建就是创建的过程,一个产品应该是一个复杂的产品,由多个组成部分构成,而产品的构建过程有一个统一的流程可以被抽象或者定义,而具体的实现是由每个 builder 类实例定制化的。
- 表示就是指一个产品的各个属性,而构建就是如何赋值这些属性,这些属性该赋予什么指等等是由 builder 来构建的。
- 所以这样的好处就是创建一个 product,product 类只是提供简单的属性定义,而具体赋予什么值,是由每个具体的 builder 定制的。比如上面例子中的 Pizza,Pizza 的属性或者不成部分就只这些,而不同的 builder 就会不予不同的值。最终是由 builder 创建出的 Pizza
- 而 director 是根据客户需要,调用不同 builder 的一个执行者,是将调用的动作进行封装,由于 builder 会提供多个执行步骤,而对于这些执行步骤的执行是不希望被用户看到的,所以进行了封装。有了 director 类
知识点
- 学习 enum 的使用
- 编程中调用一系列函数的简化流程,表明 step by step 的流程,打包一个流程的方式
[step() for step in (builder.prepare_dough,
builder.add_sauce, builder.add_topping, builder.bake)]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。