preface

Build mode is the creation mode of objects. The construction mode can separate the internal representation of a product from the production process of the product, so that a construction process can generate product objects with different internal representation.

(I) internal representation of the product

A product often has different components as parts of the product, which may or may not be objects. They are often referred to as internal representations of the product.

(ii) construction of object properties

In some cases, an object will have important properties that will not be used as a complete product until they are properly assigned. For example, an E-mail with a sender’s address, recipient’s address, subject, content, attachment, etc., cannot be sent until the most basic sender’s address has been assigned.

In some cases, properties of an object must be assigned in a certain order to make sense. One property cannot be assigned until another property is assigned.

These situations allow the nature itself to be built into complex business logic. When set, this object is equivalent to a product to be built, and these properties of the object are equivalent to the parts of the product, and the process of building the product is the process of building the parts.

Because the process of building parts is complex, the building of those parts is often externalized into another object that becomes the builder, which is returned to the client as a product object with all the parts built.

The build model uses a director object and a concrete builder object to build all the parts one by one to build the complete product object. The builder mode hides the structure of the product and the construction process of the product’s parts from the client, separates the responsibility of directing the construction process from the responsibility of the specific builder’s parts, and achieves the purpose of responsibility division and encapsulation.

The body of the

Build pattern structure

In this schematic system, the final Product Product has only two parts, namely part1 and part2. There are also two corresponding constructors, buildPart1() and buildPart2().

At the same time, it can be seen that this mode involves four roles, which are:

Abstract Builder:

Provides an abstract interface to regulate the construction of the components of a product object. What actually creates the product object in the pattern is the ConcreteBuilder role.

The concrete builder class must implement two methods required by this interface:

  1. One is product specific partsConstruction method:buildPart1()andbuildPart2();
  2. The other is returnconstructedProduct methodsretrieveResult().

In general, the number of parts a product contains corresponds to the number of construction methods. In other words, there are as many ways to build as there are parts to build.

ContreteBuilder:

This role is played by the abstract builder’s construction implementation in the context of a concrete business scenario. The role’s tasks include:

  1. implementationAbstract builderBuilderThe declared interface gives step-by-step steps through the creation of a product instance.
  2. Provide examples of products after the construction process is complete.

Director:

The class in this role calls the concrete builder role to create the product object. It should be noted that the director role does not have specific knowledge of the product class, but the specific builder role does.

Products (Product) :

Products are complex objects under construction. Generally speaking, there will be more than one product class in a system, and these product classes do not necessarily have a common interface, but can be completely unrelated.

Build pattern sample code

Product.java

public class Product {
    /** ** ** *
    private String part1;
    private String part2;

    public String getPart1(a) {
        return part1;
    }
    public void setPart1(String part1) {
        this.part1 = part1;
    }
    public String getPart2(a) {
        return part2;
    }
    public void setPart2(String part2) {
        this.part2 = part2;
    }

    @Override
    public String toString(a) {
        return "Product [part1=" + part1 + ", part2=" + part2 + "]"; }}Copy the code

Builder.java

/** * Abstract builder role ** provides part building methods and returns result methods */
public interface Builder {
    void buildPart1(a);
    void buildPart2(a);

    Product retrieveResult(a);
}
Copy the code

ConcreteBuilder.java

/** * Specific builder role */
public class ConcreteBuilder implements Builder {

    private Product product = new Product();

    /** * build part 1 */
    @Override
    public void buildPart1(a) {
        product.setPart1("Part Class 1 no. : 10000");
    }

    /** * Build part 2 */
    @Override
    public void buildPart2(a) {
        product.setPart2("Part Class 2 No. : 20000");
    }

    /** * Returns the successfully built product *@return* /
    @Override
    public Product retrieveResult(a) {
        returnproduct; }}Copy the code

Director.java

/** ** Director */
public class Director {
    /** * Creates the builder object */
    private Builder builder;

    /** * constructor, given the builder object *@paramBuilder object */
    public Director(Builder builder) {
        this.builder = builder;
    }

    /** * Product constructor method, in which the product part builder method is called. * /
    public Product construct(a){
        builder.buildPart1();
        builder.buildPart2();
        // Return to the finished product object built by Builder
        returnbuilder.construct(); }}Copy the code

Client.java

public class Client {
    public static void main(String[] args) {
        // Create a concrete builder object
        Builder builder = new ConcreteBuilder();
        // Create the director character, given the builder object
        Director director = new Director(builder);
        // Invoke the director role to create product parts. And return product build results.Product product = director.construct(); System.out.println(product); }}Copy the code

Specific steps to complete the above code:

  1. The client creates the concrete builder object;
  2. Give the specific builder object to the director;
  3. The director operates the builder object to build product parts;
  4. When the product is created, the director returns the product to the client.

The Builder pattern builds complex objects

Consider a practical business application to create an insurance contract object that has constraints on the values of many attributes and requires that the object be created to meet these constraints.

The constraint rules are as follows:

Insurance contracts can usually be signed with an individual or a company, but an insurance contract cannot be signed with both an individual and a company. There are a lot of constraints like this in this object, and using the Builder pattern to build complex objects, usually simplifies the builder pattern a little bit, because the goal is to create a complex object, so simplifying it a little bit makes the program a little bit more concise.

Specific implementation ideas are as follows:

  • Because it is usedBuilderBuilder modelTo create an object, so there’s no need to define another oneBuilderinterface, directly provide oneConcrete build classesThat’s it.
  • For creating aComplex objectThere could be many different onesOptions and Steps, simply removeThe director isDirector,The director isThe function andClientThe functions of the clients are combined, that isClientThe clientIs the equivalent ofThe director isIt toGuide builderTo build what you needComplex object.

As a result, the Builder can be abstracted to the interior of the target Product. The biggest advantage of this is that the concrete construction implementation is shielded externally. Example code is as follows:

InstranceContract.java

/** * Insurance Contract No. */
public class InstranceContract {
    /** * Insurance Contract No. */
    private String contractId;
    /** * Insured name, because there are restrictions: signed either with an individual or with a company * that is, the insured name attribute and the insured company name attribute cannot have a value at the same time. * /
    private String personName;
    /** * Name of insured company */
    private String companyName;
    /** * start time */
    private long beginDate;
    /** * The end time must be longer than the start time */
    private long endDate;
    /** * Other data */
    private String otherData;

    private InstranceContract(ConcreteBuilder builder){
        this.contractId = builder.contractId;
        this.personName = builder.personName;
        this.companyName = builder.companyName;
        this.beginDate = builder.beginDate;
        this.endDate = builder.endDate;
        this.otherData = builder.otherData;
    }

    /** * some operation of insurance contract */
    public void someOperation(a){
        System.out.println("The insurance contract number currently in operation is ["+this.contractId+"】");
        System.out.println(this);
    }

    @Override
    public String toString(a) {
        return "InstranceContract [contractId=" + contractId +
              ", personName=" + personName +
              ", companyName="+ companyName +
              ", beginDate=" + beginDate +
              ", endDate=" + endDate +
              ", otherData=" + otherData +
            "]";
    }

    public static class ConcreteBuilder {
        private String contractId;
        private String personName;
        private String companyName;
        private long beginDate;
        private long endDate;
        private String otherData;

        /** * constructor *@paramContractId Insurance Contract No. *@paramBeginDate Validity period *@paramEndDate Expiration time */
        public ConcreteBuilder(String contractId, long beginDate, long endDate) {
            this.contractId = contractId;
            this.beginDate = beginDate;
            this.endDate = endDate;
        }

        public ConcreteBuilder setPersonName(String personName) {
            this.personName = personName;
            return this;
        }

        public ConcreteBuilder setCompanyName(String companyName) {
            this.companyName = companyName;
            return this;
        }

        public ConcreteBuilder setOtherData(String otherData) {
            this.otherData = otherData;
            return this;
        }

        public InstranceContract build(a) {
            if (contractId == null || contractId.trim().length() == 0) {
                throw new IllegalArgumentException("Contract number cannot be blank.");
            }

            booleansignPerson = (personName ! =null && personName.trim().length() > 0);
            booleansignCompany = (companyName ! =null && companyName.trim().length() > 0);

            if (signPerson && signCompany) {
                throw new IllegalArgumentException("You can't have an insurance contract with both an individual and a company.");
            }

            if(! signPerson && ! signCompany) {throw new IllegalArgumentException("You can't have an insurance contract without a contract.");
            }

            if (beginDate <= 0) {
                throw new IllegalArgumentException("An insurance contract must have an effective date.");
            }

            if (endDate <= 0) {
                throw new IllegalArgumentException("An insurance contract must have an expiration date.");
            }

            if (endDate <= beginDate) {
                throw new IllegalArgumentException("The expiry date of an insurance contract must be greater than the effective date.");
            }

            return new InstranceContract(this); }}}Copy the code

The Client and Director are merged into one class, as follows:

public class Client {
    public static void main(String[] args) {
        InstranceContract.ConcreteBuilder builder =
                new InstranceContract.ConcreteBuilder("8888".1233L.2253L);

        // The director does the assembly
        InstranceContract contract =
                builder.setPersonName("Zhao four").setOtherData("Test data").build(); contract.someOperation(); }}Copy the code

conclusion

The Builder pattern applies to the following business scenarios:

  1. Complex internal structure:

The product objects that need to be generated have complex internal structures, and each internal component can itself be a complex object or just a simple component.

  1. Attribute order and dependencies:

The properties of the product objects that need to be generated depend on each other. The build model can enforce a step-by-step build process. Therefore, it is a good design idea to use the Builder pattern if one property of a product object must be assigned after another property is assigned.

  1. Attribute acquisition process is complex:

There are other objects in the system that are used during object creation that are not readily available during production object creation.


Welcome to pay attention to the technical public number: Zero one Technology Stack

This account will continue to share learning materials and articles on back-end technologies, including virtual machine basics, multithreaded programming, high-performance frameworks, asynchronous, caching and messaging middleware, distributed and microservices, architecture learning and progression.