Builder

The Builder pattern is for creating a single complex object.

Intent: To separate the construction of a complex object from its representation, so that the same construction process can create different representations.

For example,

If you don’t understand the above description, it doesn’t matter. Design patterns need to be used in daily work. Examples will help you understand better.

Build Legos

Legos are a typical random assembly scenario. You have a lot of Legos, it’s too complicated to build a small house, and you might have to follow instructions step by step, which is like creating a complex object with a lot of parameters in the right order.

If you don’t care about the fun of building lego and you just want to get a standard house quickly, what’s the fastest and easiest way to do it?

Factory line

There are many steps to make a can, and some of them, such as making a can, are universal. You can use this can to store many things, such as canned dates and canned peaches. How can the factory assembly line be flexible and extensible?

Create a database connection pool

To set up a database connection pool, we need to pass in the database address, username and password, the size of the pool to create, the location of the cache, and so on.

Considering that the database must be connected correctly, the database address and password must be verified when the database is created, and even the storage mode is related to the database type, can a simple new instantiation solve this problem?

Intention to explain

In the case of Lego, to get a house, we don’t need to care about how each piece should be placed. We just need to hand it over to the assembly factory (a person or a program) to produce a standard house. This parameter might be.sethouseType ().build() to set the type of house. Without new House(block1, block2… Block999) pass these unnecessary arguments. The assembly plant is the generator.

In the example of factory assembly line, the assembly line is the generator. An assembly line can generate factories with different functions without different combinations. The assembly line of yellow peach can be understood as new Builder(). Put in yellow peach ().build(). The assembly line of canned dates can be understood as new Builder(). Assemble cans (). Put in dates ().build(). We can reuse the most basic function of generator to assemble cans () and use it to create different products, reusing the basic assembly capabilities.

In the example of creating a database, we can set some necessary parameters before creating a database, such as new Builder().seturl ().setPassword().setType().build(), so that when we finally execute the build function, It is possible to verify the associated parameters and the resulting object cannot be modified. This is more beneficial than directly exposing the database connection pool object, and then value by value Set:

  1. Objects cannot be modified, which protects program stability and reduces maintenance complexity.
  2. Parameter associations can be verified once.
  3. There is no intermediate state before the object is created, that is, the object instance is created but some parameters are missing, which may cause the object to not work properly.

Intent: To separate the construction of a complex object from its representation, so that the same construction process can create different representations.

Once again, the separation of build and presentation means that an object Persion can not be instantiated simply by new Persion(). If it can, it is built and presented as one. The separation of construction and presentation means that Persion can only be described and cannot be instantiated through new Persion(). The instantiation work can be implemented through Builder, so that the same build process can create different instances of Persion.

In the case of Lego bricks, the House created by Lego does not come out of the new House(), but separates construction from presentation. In the factory assembly line, we create a yellow peach can, not through the new yellow peach can (), but through the assembly line in different ways. In the database example, Instead of creating the database with new DB(), we created it with Builder, which demonstrates the separation of build and presentation.

chart

  • DirectorA guide to guide the build process.
  • BuilderA generator interface that provides a set of methods for building objects and, ultimatelybuildGenerate object function, this function can do some parameter verification.
  • ConcreteBuilderBuilderThe concrete implementation of.

In fact, the Builder pattern can have a high or low level of abstraction, and we did not use the director/generator interface in any of the three examples above because we can use the simplified model when the code is not too complex.

The code example

The following example is written in javascript.

class Director {
  create(concreteBuilder: ConcreteBuilder) {
    // Create some parts
    concreteBuilder.buildA();
    concreteBuilder.buildB();
  // The verification parameters have been instantiated  return concreteBuilder.build();  } }  class HouseBuilder {  public buildA() {  // Create a house  // this.xxx = xxx  }   public buildB() {  / / brush paint  }   public build() {  // Finally create the instance  return new House(/ *.. A bunch of arguments this.xxx.. * /);  } }  // Next is the official use const director = new Director(); const builder = HouseBuilder(); const house = director.create(builder); Copy the code

The example above is the full version of the Builder pattern, abstracting the Director and Builder, as long as both are implemented strictly according to the interface, we can:

  1. Replace anyDirectorTo make any changes to the created procedure.
  2. Replace anyBuilderTo make arbitrary changes to the created implementation.

Any changes you make can result in a different house implementation. This is the benefit of the separation of creation and presentation. We can create different representations through the same build process.

The director. The create () :

  • The lego example shows the process of building a house with Lego.
  • An example of an engineering assembly line represents the assembly composition of a can.
  • In the example of creating a database connection pool, represents the process of creating a database connection pool.

Methods such as Builder and its function buildA buildB denote specific manufacturing methods, such as:

  • How to build a house, how to paint.
  • Examples in the engineering assembly line, showing how to make a can, how to add yellow peaches.
  • In the example of creating a database connection pool, how to set the database address, how to set the user name and password, etc.

In the database example, we can not only guarantee the ease of creating objects, because we do not need to pass in too many parameters, but also ensure that the objects are properly validated, and the generated instances are immutable.

More importantly, if we use full mode, we can replace Director to change the way we create the database, replace Builder to change the specific method, for example, the.setusername function does not do the specific implementation, but counts the performance, Instead of creating a database connection instance, the build() function creates a test instance.

For example, if the same method runs differently in JS and Node environments, we can implement BrowserBuild and NodeBuild with the same interface, so that we can share the same creation process and create instances that can run in different environments.

It can be seen that the use of Builder mode can ensure the convenience and stability of object creation, but also leave enough space to change the process and method of object creation, has a strong expansion.

disadvantages

Every design pattern has its own scenarios, which in turn show that there are some scenarios where it doesn’t work.

  • Instantiating objects is tedious, with many object member variables repeatedly definedsetMethod, and not as good asnewWhen the scene is simple enough, you don’t need to instantiate the object with Builder anywhere.
  • When an object has only one representation, there is no need for such a degree of abstraction.

All the above examples are relatively complex. Suppose that in our example of building a House, we do not build it with Lego bricks, but with two semi-finished templates to get a House, there is no need to use Builder mode, just new House().

And again, if we only need to produce cans and not cars, then there’s no need to abstract the Builder too much, to include the way we create cars, and finally, if our object has only one representation, there’s no need to abstract the Builder, the pipeline if we only produce cans of peaches, There is no need to make the individual stages of production detachable, because there is no need to reassemble.

conclusion

The Builder pattern is especially useful for creating complex objects, as illustrated in the following figure:

A final summary of when to use the Builder pattern: Use the Builder pattern only when the creation process allows for a different representation of the object being constructed, or when the object is so complex that the object description is worth separating from the creation process.

The discussion address is: Close reading Design Patterns – Builder Builder · Issue #273 · DT-fe /weekly

If you’d like to participate in the discussion, pleaseClick here to, with a new theme every week, released on weekends or Mondays. Front end Intensive Reading – Helps you filter the right content.

Pay attention to the front end of intensive reading wechat public account

Copyright Notice: Freely reproduced – Non-commercial – Non-derivative – Remain signed (Creative Commons 3.0 License)