Design Patterns_Creative Patterns-《Builder Patterns》

Design Patterns_Creative Patterns-《Builder Patterns》

The notes are organized from the detailed explanation of Java design patterns by dark horse programmers, 23 Java design patterns (diagram + framework source code analysis + actual combat)

overview

Separate the construction and representation of a complex object so that the same construction process can create different representations.

  • The construction of parts (responsible by Builder) and assembly (responsible by Director) are separated. Thus complex objects can be constructed. This pattern is suitable for situations where the construction process of an object is complex.
  • Due to the decoupling of construction and assembly. Different builders and the same assembly can make different objects; the same builder and different assembly sequences can also make different objects. That is to say, the decoupling of the construction algorithm and assembly algorithm is realized, and better reuse is realized.
  • The builder pattern can separate parts from their assembly process and create a complex object step by step. The user only needs to specify the type of the complex object to get the object without knowing the details of its internal construction.

structure

The Builder Pattern includes the following roles:

  • Abstract builder class (Builder): This interface stipulates the creation of those parts of the complex object, and does not involve the creation of specific component objects.

  • Concrete Builder Class (ConcreteBuilder): implements the Builder interface to complete the specific creation methods of each component of a complex product. After the construction process is complete, an instance of the product is provided.

  • Product class (Product): The complex object to be created.

  • Director class (Director): Call the specific builder to create each part of the complex object. The director does not involve the information of the specific product, and is only responsible for ensuring that the parts of the object are created completely or in a certain order.

The class diagram is as follows:

example

Create a shared bike

Producing a bicycle is a complex process that includes the production of components such as the frame and saddle. The frame is made of carbon fiber, aluminum alloy and other materials, and the seat is made of rubber, leather and other materials. For the production of bicycles, the builder pattern can be used.

Here Bike is a product, including components such as frame and seat; Builder is an abstract builder, MobikeBuilder and OfoBuilder are concrete builders; Director is a commander. The class diagram is as follows:

The specific code is as follows:

  • Product category (bicycle)

    public class Bike {
          
          
        private String frame;
        private String seat;
    
        public String getFrame() {
          
          
            return frame;
        }
    
        public void setFrame(String frame) {
          
          
            this.frame = frame;
        }
    
        public String getSeat() {
          
          
            return seat;
        }
    
        public void setSeat(String seat) {
          
          
            this.seat = seat;
        }
    }
    
  • abstract builder class

    public abstract class Builder {
          
          
    
        // 声明Bike类型的变量,并进行赋值(提高复用性)
        protected Bike mBike = new Bike();
    
        public abstract void buildFrame();
        public abstract void buildSeat();
        public abstract Bike createBike();
    }
    
  • Concrete builder class (Mobike Builder class)

    public class MobikeBuilder extends Builder {
          
          
    
        @Override
        public void buildFrame() {
          
          
            mBike.setFrame("铝合金车架");
        }
    
        @Override
        public void buildSeat() {
          
          
            mBike.setSeat("真皮车座");
        }
    
        @Override
        public Bike createBike() {
          
          
            return mBike;
        }
    }
    
  • Concrete builder class (ofo bicycle Builder class)

    public class OfoBuilder extends Builder {
          
          
    
        @Override
        public void buildFrame() {
          
          
            mBike.setFrame("碳纤维车架");
        }
    
        @Override
        public void buildSeat() {
          
          
            mBike.setSeat("橡胶车座");
        }
    
        @Override
        public Bike createBike() {
          
          
            return mBike;
        }
    }
    
  • Commander class

    public class Director {
          
          
        
        // 声明builder类型的变量
        private Builder mBuilder;
    
        public Director(Builder builder) {
          
          
            mBuilder = builder;
        }
    
        // 组装自行车的功能
        public Bike construct() {
          
          
            mBuilder.buildFrame();
            mBuilder.buildSeat();
            return mBuilder.createBike();
        }
    }
    
  • test class

    public class Client {
          
          
        public static void main(String[] args) {
          
          
            showBike(new OfoBuilder());
            showBike(new MobikeBuilder());
        }
        
        private static void showBike(Builder builder) {
          
          
            // 创建指挥者对象
            Director director = new Director(builder);
            // 让指挥者指挥组装自行车
            Bike bike = director.construct();
            System.out.println(bike.getFrame());
            System.out.println(bike.getSeat());
        }
    }
    

    output

    铝合金车架
    真皮车座
    碳纤维车架
    橡胶车座
    

Notice:

  • The above example is a regular usage of the Builder pattern. The director class Director plays a very important role in the builder pattern. It is used to guide the specific builder how to build the product, control the order of calls, and return the complete product class to the caller. But in some cases it is necessary to simplify the system structure, you can put 指挥者类和抽象建造者进行结合.

    // 抽象builder类
    public abstract class Builder {
          
          
    
        protected Bike mBike = new Bike();
    
        public abstract void buildFrame();
        public abstract void buildSeat();
        public abstract Bike createBike();
        
        public Bike construct() {
          
          
            this.buildFrame();
            this.BuildSeat();
            return this.createBike();
        }
    }
    

illustrate:

  • This really simplifies the system structure, but it also increases the responsibilities of the abstract constructor class, and it does not conform to the single responsibility principle. If construct() is too complicated, it is recommended to encapsulate it in the Director.

Advantages and disadvantages

advantage

  • The encapsulation of the builder pattern is very good. Using the builder mode can effectively encapsulate changes. In the scenario of using the builder mode, the general product class and the builder class are relatively stable. Therefore, encapsulating the main business logic in the commander class can achieve overall Relatively good stability.
  • In the builder mode, the client does not need to know the details of the internal composition of the product, and the product itself is decoupled from the product creation process, so that the same creation process can create different product objects.
  • The product creation process can be controlled more finely. Decomposing the creation steps of complex products into different methods makes the creation process clearer and more convenient to use programs to control the creation process.
  • The builder pattern is easy to extend. If there is a new requirement, it can be completed by implementing a new builder class, basically without modifying the code that has been tested before, so it will not introduce risks to the original function. Comply with the principle of opening and closing.

shortcoming

  • The products created by the builder mode generally have more in common, and their components are similar. If the products are very different, it is not suitable to use the builder mode, so its scope of use is limited.

scenes to be used

The Builder pattern creates complex objects, and the various parts of its products often face drastic changes, but the algorithm that combines them is relatively stable, so it is usually used in the following situations:

  • The created object is complex and consists of multiple parts, each part faces complex changes, but the construction sequence between the components is stable.
  • The algorithm for creating a complex object is independent of the constituent parts of that object and how they are assembled, i.e. the construction process and final representation of the product are independent.

schema extension

In addition to the above uses, the builder mode also has a common use in development, that is, when a class constructor needs to pass in many parameters, if an instance of this class is created, the code readability will be very poor, and it will be difficult to It is easy to introduce errors, and at this time, the builder pattern can be used for refactoring.

  • The code before refactoring is as follows:

    // 手机类
    public class Phone {
          
          
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;
    
        public Phone(String cpu, String screen, String memory, String mainboard) {
          
          
            this.cpu = cpu;
            this.screen = screen;
            this.memory = memory;
            this.mainboard = mainboard;
        }
    
        public String getCpu() {
          
          
            return cpu;
        }
    
        public void setCpu(String cpu) {
          
          
            this.cpu = cpu;
        }
    
        public String getScreen() {
          
          
            return screen;
        }
    
        public void setScreen(String screen) {
          
          
            this.screen = screen;
        }
    
        public String getMemory() {
          
          
            return memory;
        }
    
        public void setMemory(String memory) {
          
          
            this.memory = memory;
        }
    
        public String getMainboard() {
          
          
            return mainboard;
        }
    
        public void setMainboard(String mainboard) {
          
          
            this.mainboard = mainboard;
        }
    
        @Override
        public String toString() {
          
          
            return "Phone{" +
                    "cpu='" + cpu + '\'' +
                    ", screen='" + screen + '\'' +
                    ", memory='" + memory + '\'' +
                    ", mainboard='" + mainboard + '\'' +
                    '}';
        }
    }
    
    public class Client {
          
          
        public static void main(String[] args) {
          
          
            // 构建Phone对象
            Phone phone = new Phone("intel", "三星屏幕" ,"金士顿", "华硕");
            System.out.println(phone);
        }
    }
    

    The above constructs the Phone object in the client code and passes four parameters. What if there are more parameters? The readability of the code and the cost of use are relatively high.

  • Code after refactoring:

    // 手机类
    public class Phone {
          
          
    
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;
    
        // 私有构造方法,传递一个建造者
        private Phone(Builder builder) {
          
          
            cpu = builder.cpu;
            screen = builder.screen;
            memory = builder.memory;
            mainboard = builder.mainboard;
        }
    
        // 内部类-建造者类
        public static final class Builder {
          
          
            private String cpu;
            private String screen;
            private String memory;
            private String mainboard;
    
            public Builder() {
          
          }
    
            public Builder cpu(String val) {
          
          
                cpu = val;
                return this;
            }
            public Builder screen(String val) {
          
          
                screen = val;
                return this;
            }
            public Builder memory(String val) {
          
          
                memory = val;
                return this;
            }
            public Builder mainboard(String val) {
          
          
                mainboard = val;
                return this;
            }
            // 使用构建者创建Phone对象
            public Phone build() {
          
          
                return new Phone(this);
            }
        }
        
        @Override
        public String toString() {
          
          
            return "Phone{" +
                    "cpu='" + cpu + '\'' +
                    ", screen='" + screen + '\'' +
                    ", memory='" + memory + '\'' +
                    ", mainboard='" + mainboard + '\'' +
                    '}';
        }
    }
    
    // 测试类
    public class Client {
          
          
        public static void main(String[] args) {
          
          
            // 创建手机对象 通过构建者对象获取手机对象
            Phone phone = new Phone.Builder()
                    .cpu("intel")
                    .mainboard("华硕")
                    .memory("金士顿")
                    .screen("三星")
                    .build();
            System.out.println(phone);
        }
    }
    

    The refactored code is more convenient to use, improves the readability of the code, and can also improve development efficiency to some extent.

    The construction order of the original builder mode is determined by the conductor class, but now the order of construction is handed over to the client.

    From the perspective of software design, the requirements for programmers are relatively high.

Summarize

reference

Creator mode comparison

Factory method pattern vs builder pattern

  • The factory method pattern focuses on the creation of the overall object; while the builder pattern focuses on the process of component construction, intending to create a complex object through precise construction step by step.
  • Let's give a simple example to illustrate the difference between the two. If you want to make a superman, if you use the factory method model, you will directly produce a superman with infinite strength, ability to fly, and wear underwear; if you use the builder model, You need to assemble the hands, head, feet, torso and other parts, and then wear the underwear outside, so a superman was born.

Abstract Factory Pattern VS Builder Pattern

  • The abstract factory pattern realizes the creation of product families. A product family is such a series of products: a product combination with different classification dimensions. The abstract factory pattern does not need to care about the construction process, but only cares about which products are produced by which factories. .
  • The builder mode requires building products according to a specified blueprint, and its main purpose is to produce a new product by assembling spare parts.
  • If the abstract factory pattern is regarded as an auto parts production factory, which produces a product family of products, then the builder pattern is a car assembly factory, which can return a complete car through the assembly of parts.

Guess you like

Origin blog.csdn.net/weixin_53407527/article/details/128627841