Design Mode II: Builder mode

Builder mode

Want to create an object composed of multiple parts, and he's constitution needs to be done step by step. Only when the various parts are created, the object is complete. Then you need the builder pattern

Builder design pattern: the construction process of a complex object and its separation performance, the construction process can be used to create multiple different performance.

In this mode there are two players: Builders and commander

Builder responsible for creating complex objects of various components.

Commander course builder instance control construction.

The difference between the builder pattern and factory pattern

1. factory pattern to create objects in a single step, and the builder pattern to create an exclusive multiple steps, and almost always use the same conductor;

2. In the factory mode, it will immediately return a good object is created; and in the builder pattern, only when necessary client code was explicitly request the commander returns the final object.

In fact, django-widgy in the builder pattern just been applied. django-widgy Django is a third-party editor, expand the tree can be used as a content management system (Content Management System, CMS). It contains a Web page builder, with different layouts created in HTML pages.

Apple's model 1. Applications built

Which sets a class type, such an approach may be disabled directly instantiate a simple class

An example of Apple, the manufacturer of the hardware specifications are all hiding, customers only know to buy a particular brand and model of notebook

We can see only AppleFactoryinstance of the class, but other production parameters were hiding, the production process can not be directly instantiated MacMini14class
parameters of the process, so buyers do not care about the internal production process

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 '\n'.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)

Use named parameters

Using the argument list expansion

The difference between the factory model and model builders

  1. Factory pattern to create objects in a single step, the creator mode to create objects in multiple steps, and almost always use a commander.
  2. In the factory mode, it will immediately return a good object is created; and in the builder pattern, only when necessary client code was explicitly request the commander returns the final target

2. Case II: provides instructions to the manufacturer as a commander, you want to make the computer

First instantiated HardwareEngineer, calling and parameter passing construct_computer(self, memory, hdd, gpu), go instantiated ComputerBuilder()->Computer()

List-style execution function

        [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 '\n'.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()

As can be seen, class instantiation is performed layer by layer, but have conductor main()was performed only when it is first instantiated

3. Use the Builder (builder) mode making Pizza

Making pizza requires a specific sequence in order to make:

We must first prepare: Ingredients, sauces, dough

Then, the dough ingredients and seasoning sprinkle

Pizza according to the requirements of different, different baking time depends on the ingredients used and the thickness of the dough

There are two application builder:

  1. Margaret made pizza (MargaritaBuilder)
  2. Making butter bacon pizza (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. chain Builders method call (fluent builder): Pizza chain method

Pizza class contains PizzaBuilder ()

build () to instantiate Pizza (), passing parameters self, is the parameter builder Pizza

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 '\n'.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)

Guess you like

Origin www.cnblogs.com/myt2000/p/11570037.html