建造者模式
浏览 720
课文
情景
你是一名赛百味门店的员工,每天主要的工作就是将三明治的食材:面包、肉、酱料分别准备好,等待顾客指定将其包装成一个完整的三明治。准备食材的代码模拟如下:
# 假设组成三明治的三种食材中种类如下:
class WholeWheatBread:
def __init__(self):
self.name = '全麦面包'
self.price = 5.0
class ChickenBreast:
def __init__(self):
self.name = '鸡胸肉'
self.price = 10.0
class BlackPepperSauce:
def __init__(self):
self.name = '黑椒酱'
self.price = 1.0
bread = WholeWheatBread()
meat = BlackPepperSauce()
sauce = BlackPepperSauce()
食材已经准备好了,接下来开始组装三明治,下面记作代码 Ⅰ:
# 初始化三明治时需要分别传入面包类、肉类以及酱料类
class Sandwich:
def __init__(self, bread, meat, sauce):
self.bread = bread.name
self.meat = meat.name
self.sauce = sauce.name
# 提供获取三明治组成与总价的函数
def getItems(self):
print("面包: " + self.bread)
print("肉: " + self.meat)
print("酱料: " + self.sauce)
def getCost(self):
cost = self.bread.price + self.meat.price + self.sauce.price
print("花费:¥", cost)
sandwich = Sandwich(bread, meat, sauce)
sandwich.getItems()
输出:
面包:全麦面包
肉:鸡胸肉
酱料:黑椒酱
花费:¥16
我们把上面的代码改造一下,记作代码 Ⅱ:
# 提供一个三明治的建造类,其中分别提供了面包、肉和酱料的添加方法
class SandwichBuilder:
def order_bread(self, bread):
self.bread = bread
def order_meat(self, meat):
self.meat = meat
def order_sauce(self, sauce):
self.sauce = sauce
# 最后将所有的组分作为参数传进Sandwich类里
def build(self):
return Sandwich(self)
# 改造一下Sandwich类,让它只接受一个参数sandwich_builder
class Sandwich:
def __init__(self, sandwich_builder):
self.bread = sandwich_builder.bread.name
self.meat = sandwich_builder.meat.name
self.sauce = sandwich_builder.sauce.name
# 准备好食材
bread = WholeWheatBread()
meat = BlackPepperSauce()
sauce = BlackPepperSauce()
# 实例化建造者,并调用建造者的方法添加食材
builder = SandwichBuilder()
builder.order_bread(bread)
builder.order_meat(meat)
builder.order_sauce(sauce)
# 最后调用建造者的build方法,返回一个Sandwich类的实例
sandwich = builder.build()
sandwich.getItems()
跟上面一样的输出:
面包:全麦面包
肉:鸡胸肉
酱料:黑椒酱
花费:¥16
这种写法,就是典型的建造者模式(Builder Pattern)。
正文
建造者模式的定义是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。它通常由几部分构成:
- 产品类(Sandwich 类等)
- 建造类(SandwichBuilder 类)
- 指挥类(下面会细说)
用上面的例子来解释一下这个定义:「复杂对象的构建」是指 SandwichBuilder 类里的order_xxx()
等方法,而「复杂对象的表示」则是指 SandwichBuilder 类里的build()
方法。那么后半句怎么理解呢?回到上面代码,如果增加其中一种食材:
# 假设酱料里有个番茄酱
class Ketchup:
def __init__(self):
self.name = '番茄酱'
self.price = 0.5
那么我想要一个加番茄酱的三明治,只需要仿照代码 Ⅱ 的步骤,将BlackPepperSauce()
换成Ketchup()
即可:
sauce = Ketchup()
输出则会变成:
面包:全麦面包
肉:鸡胸肉
酱料:番茄酱
花费:¥15.5
同样的构建过程(面包夹肉加酱料),换了组成部分的类型(将黑椒酱换成番茄酱)之后就变成了不同的表示(不一样的三明治),这就达到了用少量代码大大扩展了复杂对象的种类数量的目的。
这时候可能有人要问了:那代码 Ⅰ 不是比代码 Ⅱ 更少吗?为什么还要多余写一个 Builder 类呢?
如果能想到这一层,说明你确实是一个爱思考的开发者。跟工厂类模式一样,实际的业务场景中可能会具有较为复杂的逻辑判断过程,如果全部写在类初始化函数里,会导致代码过于臃肿,难以维护和扩展:
# 代码Ⅰ修改
class Sandwich:
def __init__(self, bread, meat, sauce):
# 假设三样东西都得有
if not bread.name or not meat.name or not sauce.name:
print('住手,这根本不是三明治!')
# 假设黑椒酱只能配牛排,不然会报错
elif sauce.name == '黑椒酱' and meat.name != '牛排':
print('对不起,我们这边规定黑椒酱必须配牛排哦')
elif ...
# 代码Ⅱ修改
class SandwichBuilder:
def order_bread(self, bread):
self.bread = bread
def order_meat(self, meat):
self.meat = meat
def order_sauce(self, sauce):
if sauce.name == '黑椒酱' and self.meat.name != '牛排':
print('对不起,我们这边规定黑椒酱必须配牛排哦')
else:
self.sauce = sauce
def build(self):
if not bread.name or not meat.name or not sauce.name:
print('住手,这根本不是三明治!')
else:
return Sandwich(self)
这样就能保证在业务场景变更时,修改的代码的影响范围尽可能小。
什么是指挥类?
(待更新)
评论
暂无评论