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 AppleFactory
instance of the class, but other production parameters were hiding, the production process can not be directly instantiated MacMini14
class
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)
Using the argument list expansion
The difference between the factory model and model builders
- Factory pattern to create objects in a single step, the creator mode to create objects in multiple steps, and almost always use a commander.
- 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:
- Margaret made pizza (MargaritaBuilder)
- 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)