建造者模式

浏览 769

课文

情景

你是一名赛百味门店的员工,每天主要的工作就是将三明治的食材:面包、肉、酱料分别准备好,等待顾客指定将其包装成一个完整的三明治。准备食材的代码模拟如下:

# 假设组成三明治的三种食材中种类如下:
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)

这样就能保证在业务场景变更时,修改的代码的影响范围尽可能小。

什么是指挥类?

(待更新)

评论

登录参与讨论

暂无评论

共 0 条
  • 1
前往
  • 1