zoukankan      html  css  js  c++  java
  • 设计模式二:建造者模式

    建造者模式

    想要创建一个由多个部分构成的对象,而且他的构成需要一步接一步地完成。只有当各个部分都创建好,这个对象才是完整的。这时就需要建造者模式

    建造者设计模式:将一个复杂对象的构造过程与其表现分离,构造过程可用于创建多个不同的表现。

    该模式中有两个参与者:建造者指挥者

    建造者负责创建复杂对象的各个组成部分。

    指挥者使用建造者实例控制建造的过程。

    建造者模式与工厂模式的区别

    1.工厂模式以单个步骤创建对象,而建造者模式以多个步骤创建独享,并且几乎始终使用同一个指挥者;

    2.在工厂模式下,会立即返回一个创建好的对象;而在建造者模式下,仅在需要时客户端代码才显示地请求指挥者返回最终的对象。

    其实在django-widgy中建造者模式就得到了实际应用。django-widgy是一个Django的第三方树编辑器扩展,可用作内容管理系统(Content Management System, CMS)。它包含一个网页构建器,用在创建不同布局的HTML页面。

    1. 建造者模式的苹果电脑应用案例

    类里面套一个类,这种写法可以禁止直接实例化一个类的简洁方式

    一个苹果电脑的例子,制造商将所有的硬件规格都隐藏了起来,客户只知道去买某个品牌和型号的笔记本

    可以看到只有AppleFactory类实例化, 但生产的其他参数都隐藏了起来,无法直接实例化生产过程MacMini14
    过程的参数,让购买者无需关心内部生产的过程

    MINI14 = '1.4GHZ Mac mini'
    
    class AppleFactory:
    
        class MacMini14:
    
            def __init__(self):
                self.memory = 4 # 单位为GB
                self.hdd = 500 # 单位为GB
                self.gpu = 'Intel HD Graphics 5000'
    
            def __str__(self):
                info = ('Model: {}'.format(MINI14),
                        'Memory: {}GB'.format(self.memory),
                        'Hard Disk: {}GB'.format(self.hdd),
                        'Graphics Card: {}'.format(self.gpu))
                return '
    '.join(info)
    
        def build_computer(self, model):
            if (model == MINI14):
                return self.MacMini14()
            else:
                print("I don't know how to build {}".format(model))
    
    if __name__ == '__main__':
        afac = AppleFactory()
        mac_mini = afac.build_computer(MINI14)
        print(mac_mini)
    

    使用命名参数

    使用实参列表展开

    工厂模式和建造者模式的区别

    1. 工厂模式以单个步骤创建对象,创建者模式以多个步骤创建对象,并且几乎始终会使用一个指挥者。
    2. 在工厂模式下,会立即返回一个创建好的对象;而在建造者模式下,仅在需要时客户端代码才显示地请求指挥者返回最终的对象

    2. 案例二:作为指挥者向制造商提供指令,制作想要的电脑

    首先实例化HardwareEngineer,调用并传参construct_computer(self, memory, hdd, gpu),再去实例化ComputerBuilder()--> Computer()

    列表式执行函数

            [step for step in (self.builder.configure_momory(memory),
                               self.builder.configure_hdd(hdd),
                               self.builder.configure_gpu(gpu))]
    
    
    class Computer:
    
        def __init__(self, serial_number):
            self.serial = serial_number
            self.memory = None  # 单位为GB
            self.hdd = None     # 单位为GB
            self.gpu = None
    
        def __str__(self):
            info = ('Memory: {}GB'.format(self.memory),
                    'Hard Disk: {}GB'.format(self.hdd),
                    'Graphics Card: {}'.format(self.gpu))
            return '
    '.join(info)
    
    
    class ComputerBuilder:
    
        def __init__(self):
             self.computer = Computer('AG23385193')
    
        def configure_momory(self, amount):
            self.computer.memory = amount
    
        def configure_hdd(self, amount):
            self.computer.hdd = amount
    
        def configure_gpu(self, gpu_model):
            self.computer.gpu = gpu_model
    
    
    class HardwareEngineer:
    
        def __init__(self):
            self.builder = None
    
        def construct_computer(self, memory, hdd, gpu):
            self.builder = ComputerBuilder()
            [step for step in (self.builder.configure_momory(memory),
                               self.builder.configure_hdd(hdd),
                               self.builder.configure_gpu(gpu))]
    
    
        @property
        def computer(self):
            return self.builder.computer
    
    
    def main():
        engineer = HardwareEngineer()
        engineer.construct_computer(hdd=500, memory=8, gpu='GeForce GTX 650 Ti')
        computer = engineer.computer
        print(computer)
    
    if __name__ == '__main__':
        '''
        通过HardwareEngineer(传参调用ComputerBuilder,可以使用其他类也可以) --> ComputerBuilder --> Computer(负责打印输出数据)
        '''
        main()
    
    
    

    可以看出,类实例化是一层一层的进行的,但是得指挥者main()却只是执行时进行了一次实例化

    3. 使用建造者(builder)模式制作Pizza

    制作披萨需要特定的顺序,才能制作:

    先要准备:配料、调味料、生面团

    然后,生面团上面撒上调味料和配料

    根据不同的pizza的要求,有不同的烘焙时间,依赖于生面团的厚度和使用的配料

    应用中有两个建造者:

    1. 制作玛格丽特披萨(MargaritaBuilder)
    2. 制作奶油熏肉披萨(CreamyBaconBuilder)

    from enum import Enum
    import time
    
    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:
    
        def __init__(self, name):
            self.name = name
            self.dough = None
            self.sauce = None
            self.topping =[]
    
        def __str__(self):
            return self.name
    
        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):
            self.pizza = Pizza('margarita')
            self.progress = PizzaProgress.queued
            self.baking_time = 5
    
        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')
            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 creme fraiche sauce to your creamy bacon')
            self.pizza.sauce = PizzaSauce.creme_fraiche
            time.sleep(STEP_DELAY)
            print('done with the creme fraiche 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, mushroom, red onion, oregano)')
    
        def bake(self):
            self.progress = PizzaProgress.baking
            print('baking your creamy bacon for {} second'.format(self.baking_time))
            time.sleep((self.baking_time))
            self.progress = PizzaProgress.ready
            print('your creamy bacon is ready')
    
    
    class Waiter:
    
        def __init__(self):
            self.builder = None
    
        def construct_pizza(self, builder):
            self.builder = builder
            [step() for step in (builder.prepare_dough,
                                 builder.add_sauce, builder.add_topping, builder.bake)]
    
        @property
        def pizza(self):
            return self.builder.pizza
    
    
    def validata_style(builders):
        try:
            pizza_style = input('What pizza would you like, [m]argarita or [c]reamy bacon? ')
            builder = builders[pizza_style]()
            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 = validata_style(builders)
        print()
        waiter = Waiter()
        waiter.construct_pizza(builder)
        pizza = waiter.pizza
        print()
        print('Enjoy your {}!'.format(pizza))
    
    if __name__ == '__main__':
        main()
    
    

    4.链式调用建造者方法(流利的建造者):Pizza链式方法

    Pizza类中包含PizzaBuilder()

    build() 实例化Pizza(), 传入参数self,就是Pizza的形参builder

    class Pizza:
    
        def __init__(self, builder):
            self.garlic = builder.garlic
            self.extra_cheese = builder.extra_cheese
    
        def __str__(self):
            garlic = 'yes' if self.garlic else 'no'
            cheese = 'yes' if self.extra_cheese else 'no'
            info = ('Garlic: {}'.format(garlic), 'Extra cheese: {}'.format(cheese))
            return '
    '.join(info)
    
        class PizzaBuilder:
    
            def __init__(self):
                self.extra_cheese = False
                self.garlic = False
    
            def add_garlic(self):
                self.garlic = True
                return self
    
            def add_extra_cheese(self):
                self.extra_cheese = True
                return self
    
            def build(self):
                # 实例化Pizza(), 传入参数self,就是Pizza的形参builder
                return Pizza(self)
    
    if __name__ == '__main__':
        # Pizza类中包含PizzaBuilder()
        pizza = Pizza.PizzaBuilder().add_garlic().add_extra_cheese().build()
        print(pizza)
        # a = Pizza
        # print(a)
        # b = a.PizzaBuilder()
        # print(b)
        # c = b.add_garlic().add_extra_cheese().build()
        # print(c)
    
    
  • 相关阅读:
    ADERA3 省选模拟赛 SPOJ LMCONST
    TYVJ 1730 二逼平衡树 线段树套平衡树
    BZOJ 1059 [ZJOI2007]矩阵游戏 二分图匹配
    BZOJ 1056 [HAOI2008]排名系统 Splay+Hash
    OI教会我的
    BZOJ 1055 [HAOI2008]玩具取名 DP
    BZOJ 1058 [ZJOI2007]报表统计 Splay
    为自己而奋斗
    [总结]高斯消元&XOR方程
    我 的 2013
  • 原文地址:https://www.cnblogs.com/myt2000/p/11570037.html
Copyright © 2011-2022 走看看