Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

preface

The design pattern has been encapsulated in lombok as a @Builder annotation, so the wheel doesn’t need to be built, but we still need to understand how it is implemented at the bottom. The Builder design pattern is personally more about writing “elegant” code. Especially if there are a lot of arguments using chain calls in builder mode makes the code much cleaner.

The idea plugin GenrateAllGetSet is recommended here. It is also useful to generate all set methods of an object in one piece, especially when you do not want to write a generic builder object.

define

The Builder pattern separates the complex build process from the concrete presentation of objects. The client only needs to know the parameters required by the builder, not the details of the build, and can customize different objects according to the operation of the build. This pattern mainly solves the problem of the complex build process and focuses on the “configuration” of the object’s build process.

The advantages and disadvantages

Advantages:

  1. The products you build must have something in common; you cannot use the same builder for completely different products.

  2. If internal changes are complex, there will be many construction classes, and nesting is easy.

Disadvantages:

  1. If the internal changes of the product are complex, many specific builder classes may need to be defined to implement the changes, resulting in a large system.
  2. Products created by the Builder model tend to have more in common, with similar components; The Builder pattern is not suitable for products that vary widely, so its scope is limited.

Application scenarios

  1. A large number of objectssetMethod, which may misrepresent parameters, can be used by the builderChain callsBuild parameters build objects.
  2. According to different combination parameters to achieve different effects suite.
  3. Using factory + Builder mode, you can not only build different products, but also customize the build details of the products. ** But not to be confused with the factory, which is responsible for decoupling the production and use processes, while the builder is more concerned with the details of the build.

Structure:

This mode is quite special. I have a deep impression on the template code, but I don’t think it is necessary to know about this structure diagram. Therefore, I will directly use the screenshot on the network for a brief introduction:

Effective Java application number two

The second article in the book Effective Java discusses the use of a builder to compensate for multiple constructor arguments, as shown in the following example:

 public User(String userId, String orgId, String orgName, String merchNo, String userName, String userRealName, String userPwd) {
        this.userId = userId;
        this.orgId = orgId;
        this.orgName = orgName;
        this.merchNo = merchNo;
        this.userName = userName;
        this.userRealName = userRealName;
        this.userPwd = userPwd;
    }
Copy the code

Since written as easy to preach fault parameters, and determine if join the Boolean parameter is hell, such as when we build the object will be this kind of situation, the following constructor builds basic no one remember the parameters of the object sequence, basic it is visible to the naked eye check is not easy to get wrong,

User user = new User("xx"."xx"."xx"."xx"."xx"."xx"."xx");
Copy the code

We would normally choose to use a set method instead, such as the following, but this method would directly cause the immutable properties of the object to be destroyed. Here is the use of the set method mentioned above. For example, on a MAC computer, Just place the cursor over the object and press Option +Enter (make sure all parameters you need have the set method, because the reflection of the plugin’s underlying object-based methods is generated).

After the generation is complete, you can see the following effect, but it is obvious that this approach breaks the encapsulation of the object:

In order to solve the above problem, we use the builder pattern to for such a code refactoring, which is a template pattern the builder of the code, here by private constructor, using builder for a specific instance of a layer of “protection”, so directly for the objects to the generation process of closed and ensure the safety of the object’s thread:

public class UserBuilder {

    /** * user id */
    private final String userId;

    /** * id */
    private final String orgId;

    /** * Organization name */
    private final String orgName;

    public static class Builder {
        /** * user id */
        private String userId;

        /** * id */
        private String orgId;

        /** * Organization name */
        private String orgName;

        public Builder(String userId, String orgId, String orgName) {
            this.userId = userId;
            this.orgId = orgId;
            this.orgName = orgName;
        }

        public Builder userId(String userId) {
            this.userId = userId;
            return this;
        }

        public Builder orgId(String orgId) {
            this.orgId = orgId;
            return this;
        }

        public Builder orgName(String orgName) {
            this.orgName = orgName;
            return this;
        }

        public UserBuilder build(a){
            return new UserBuilder(this); }}private UserBuilder(Builder builder) {
        this.userId = builder.userId;
        this.orgId = builder.orgId;
        this.orgName = builder.orgName; }}Copy the code

The actual case

This example is also a simplification of the effective Java book on builders. It shows the advanced use of constructors and the dynamic extension of constructors. The code is presented directly here.

The general purpose of the builder is to implement dynamic character building. At the top level of the abstract object and the builder, abstract methods are defined for subclasses to implement. Subclasses can implement concrete product implementation as well as the details of the builder’s builder.

public abstract class AbstractUser {

    private final NATURE nature;

    protected enum NATURE {LIVELY, MELANCHOLY, LONELY, NORMAL}

    abstract static class Builder<T extends Builder<T>> {

        private NATURE nature = LIVELY;

        /** * build method **@return* /
        protected abstract T build(a);

        /** * requires subclasses to implement **@return* /
        protected abstract AbstractUser process(a);


    }

    public AbstractUser(Builder builder) {
        this.nature = builder.nature; }}Copy the code

Concrete implementation products and subclassing builders, as you can see, can fully leverage the builder pattern in this way, not only allowing dynamic scaling, but also decoupling details from common processing, but using this design pattern requires some programming experience. At the same time, it is recommended to use the following writing method if you are familiar with the design pattern, otherwise it is recommended to use other design pattern rewriting, because this writing method obviously has a certain impact on the readability.

public class ConcreteUser extends AbstractUser{

    private final NATURE nature;

    private ConcreteUser(ConcreteBuilder concreteBuilder) {
        super(concreteBuilder);
        this.nature = concreteBuilder.nature;
    }

    public static class ConcreteBuilder extends AbstractUser.Builder{

        private final NATURE nature;

        public ConcreteBuilder(NATURE na) {
            this.nature = na;
        }

        @Override
        protected ConcreteUser process(a) {
            System.err.println("Processing logic one");
            return new ConcreteUser(this);
        }

        @Override
        public Builder build(a) {
            return this; }}}Copy the code

conclusion

In short, the builder mode or the old and sincere use of annotations is more appropriate, in most cases with annotations can also be done, for the builder’s deep extension needs deep programming experience and technical support, which is the point we need to progress and learn, but writing such code undoubtedly requires a lot of code writing practice.

Write in the last

The Builder pattern is also a well-understood design pattern, one that can be quickly recalled once you know the template code.