This post is part of the third session of the Nuggets Creators Training Camp.Digg project | Creator Boot Camp phase 3 is underway, “write” to make a personal impact.

📖 preface

Books are not to be read but to be used

Here I want to emphasize the learning method, there are always a lot of small partners have doubts about learning knowledge, obviously read, read also understand, but when it comes to the actual use, but not on. Or sometimes I think it would be better not to have more vivid cartoons or some comparison, of course these ways may speed up a newcomer’s understanding of knowledge. But as long as you watch learning videos as movies and learning books as stories, it’s hard to master the stack. You can’t really master this skill unless you put it to use, dig deeper word by word, explore a little bit, and clear away all the blind spots you encounter.

🚀 Builder pattern

When we want to create an object with multiple parts, and their construction needs to be done step by step, the object is not complete until all the parts have been created. This is where the builder’s design pattern comes in.

  • Builder Pattern, also known as generator Pattern, is an object construction Pattern. It can abstract the construction process of complex objects (abstract classes), so that different implementation methods of this abstract process can construct objects with different manifestations (attributes).
  • The Builder pattern, which creates a complex object step by step, allows users to build complex objects simply by specifying their type and content, without needing to know the specific build details inside.
  • Main solution: main solution in the software system, sometimes faced with “a complex object” to create work, which is usually composed of each part of the sub-object with a certain algorithm; The pieces of this complex object often face drastic changes due to changing requirements, but the algorithms that put them together are relatively stable.
  • When to use: When some basic components do not change, but the combination often changes.
  • How to solve it: Separate change from immobility.
  • Key code: Builder: creates and provides instances, director: manages dependencies of instances built.
  • Example: When you go to KFC, the hamburger, Coke, French fries, fried chicken wings and so on remain the same, but their combination is constantly changing, resulting in the so-called “set meal”.
  • Advantages: 1, independent builder, easy to expand. 2, easy to control the details of risk.
  • Disadvantages: 1, the product must have something in common, the scope is limited. 2. If the internal changes are complex, there will be many construction classes.
  • Usage scenarios: 1. The object to be generated has a complex internal structure. 2. The internal properties of the object to be generated depend on each other.
  • Note: The difference from factory mode is that builder mode is more concerned with the order in which parts are assembled.

According to Master Python Design Patterns, the Builder pattern is often used to complement the factory pattern, especially in the following scenarios:

  1. You want an object to behave differently, and you want to decouple the object’s construction from its representation.
  2. Requires that an object be created at one point in time but accessed at a later point in time.

Personal Understanding:

Since the factory mode was introduced earlier, here is the creator mode for comparison:

Factory mode is like buying a complete computer directly by typing in the keywords from a treasure. The creator model, on the other hand, is more like taking a computer shell and piecing together parts step by step into the shell to get a complete computer.

Application Scenarios:

One of the most common scenarios is an ORM that operates on a database. Recall that lazy loading, an important concept in ORM, is actually the most common application of the Builder pattern.

The ORM object is constructed at the beginning, but the data is not actually queried, but the database is queried when the specific data is needed. In addition, different tables are queried according to different objects.

Example :(from translated reviewer’s condensed code in the book)

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):
            return Pizza(self)

if __name__ == '__main__':
    pizza = Pizza.PizzaBuilder().add_garlic().add_extra_cheese().build()
    print(pizza)
Copy the code

This is a process of adding ingredients to pizza, that is, a original pizza was created at the beginning, then ingredients were added to pizza step by step through PizzaBuilder, and finally a complete pizza was obtained.

There is also a chain call, which is not a magic thing, except that every method in the constructor class returns itself after adding a property to the object.

🐱 🏍 instance

The Builder mode can be used to describe how KFC creates meals: Package is a complex object, it usually contains staple food (such as hamburger, chicken roll, etc.) and beverages (such as fruit juice, coke, etc.) part of different package have different part of the KFC attendant can according to customer requirements, step by step, assembling these components, to construct a complete package, and then return to the customer.

# Specific product object
class Menu:
    Menu_A=[]
    Menu_B=[]
    def set_MenuA(self,item) :
        self.Menu_A.append(item)
    def set_MenuB(self,item) :
        self.Menu_B.append(item)
    def get_MenuA(self) :
        return self.Menu_A
    def get_MenuB(self) :
        return self.Menu_B

# Builder
Create an abstract interface specified by the various parts of the Product object.
class Product:
    product = Menu()
    def build_hanbao(self) :
        pass
    def build_jiroujuan(self) :
        pass
    def build_kele(self) :
        pass
    def build_shutiao(self) :
        pass

# ConcreteBuilder
Implement abstract interfaces, build and assemble parts.
# set A
class product_A(Product) :
    def __init__(self) :
        self.producttype="A"
    def build_hanbao(self) :
        self.hanbao="Hamburger"
        self.product.set_MenuA(self.hanbao)
    def build_kele(self) :
        self.kele="Coke"
        self.product.set_MenuA(self.kele)
    def getType(self) :
        return self.producttype

# set B
class product_B(Product) :
    def __init__(self) :
        self.producttype = "B"
    def build_shutiao(self) :
        self.shutiao="French fries"
        self.product.set_MenuB(self.shutiao)
    def build_jiroujuan(self) :
        self.jiroujuan="Chicken wrap"
        self.product.set_MenuB(self.jiroujuan)
    def build_kele(self) :
        self.kele="Coke"
        self.product.set_MenuB(self.kele)
    def getType(self) :
        return self.producttype

#Director
class Make:
    def __init__(self) :
        self.builder = None
    def build_product(self, builder) :
        self.builder = builder
        print(builder.producttype)
        if builder.producttype == "A":
            [step() for step in (builder.build_hanbao,
            builder.build_kele)]
        if builder.producttype == "B":
            [step() for step in (builder.build_shutiao,
                                 builder.build_jiroujuan,
                                 builder.build_kele)]


# Different type selection
def validate_style(builders) :
    global valid_input
    try:
        print('Set A: Hamburger, Coke'+'\n'
              'Set B: French fries, chicken wrap, Coke')
        product_style = input('Please enter your choice:' )
        builder = builders[product_style]()
        valid_input = True
    except KeyError as err:
        print(Sorry, we don't have this package, please choose again. ')
        return (False.None)
    return (True, builder,product_style)

# main function
def main() :
    builders = dict(A=product_A, B=product_B)
    valid_input = False
    while not valid_input:
        valid_input, builder,product_style = validate_style(builders)
    Waiter = Make()
    Waiter.build_product(builder)
    if product_style == "A":print(builder.product.get_MenuA())
    else:print(builder.product.get_MenuB())

if __name__ =="__main__":
    main()
Copy the code

Results:

Set meal A: Hamburger, Coke set B: French fries, chicken roll, Coke Please enter your choice: A A [' hamburger ', 'Coke ']Copy the code

🎉 finally

  • We learned how to use the Builder design pattern. You can use the Builder pattern to create objects in scenarios where the factory pattern (factory method or abstract factory) does not apply. The Builder mode is a better choice than the factory mode in several situations.

    • You want to create a complex object (an object is made up of multiple parts that go through different steps, perhaps in a particular order)
    • You want an object to behave differently, and you want to decouple the object’s construction from its representation
    • You want to create an object at a point in time but access it at a later point in time
  • For more references, see here:The Blog of Chan Wing Kai

  • Like the small partner of the blogger can add a concern, a thumbs-up oh, continue to update hey hey!