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)
    
    
  • 相关阅读:
    android 75 新闻列表页面
    android 74 下载文本
    android 73 下载图片
    android 72 确定取消对话框,单选对话框,多选对话框
    android 71 ArrayAdapter和SimpleAdapter
    android 70 使用ListView把数据显示至屏幕
    maven如何将本地jar安装到本地仓库
    Centos6.7搭建ISCSI存储服务器
    解决maven打包编译出现File encoding has not been set问题
    MySQL 解决 emoji表情 的方法,使用utf8mb4 字符集(4字节 UTF-8 Unicode 编码)
  • 原文地址:https://www.cnblogs.com/myt2000/p/11570037.html
Copyright © 2011-2022 走看看