Builder mode--Master asked me to make alchemy

Primer

It is said that Xiaoshuai has worked diligently in the Xiancao Pharmacy at the foot of Huashan Mountain for many years, and has been promoted from a handyman to a factory manager, responsible for the production of the treasure of the pharmacy--Super Black Jade Intermittent Ointment.

Super Black Jade Intermittent Ointment is a rare and secret medicine with the power of regeneration and incomparable magic. Its price is comparable to gold. After taking it, it immediately restores 2500 points of life. It also has super efficacy and can restore 1000 points of internal strength at the same time.

This medicine is so miraculous, its refining process is extremely complicated, and its quality is difficult to control. Although the masters in the factory have rich experience in refining medicine, they always miss some things, resulting in good and bad efficacy of the product. Customers have many complaints about this . The master ordered Xiaoshuai to reform the process within three months to prevent such problems.

Xiaoshuai was ordered in the face of danger, and immediately started to work, sorting out all the procedures of Super Black Jade Intermittent Ointment:

  1. Deploy all kinds of precious medicinal materials in proportion
  2. Soak in the mountain spring at the foot of Huashan for seven days and seven nights
  3. After soaking, add the secret medicine and mix well
  4. Refined in the Bagua Furnace for seventy-seven forty-nine days
  5. Dry in the sun for ten days on the top of Mount Hua, absorbing the essence of the sun and the moon
  6. Sealed in a special wooden box

Because the process flow is very complicated, Xiaoshuai made a list of the production process. Everyone operates according to this list. Whether it is an experienced master or a new apprentice, they must strictly follow the steps on the list. Something went wrong.

As for how this list should be used in production? Xiaoshuai used to be a programmer, so he used code to write out the whole process. A design pattern is also used here. Let's take a look.

build mode

Builder Pattern: The construction of a complex object is separated from its representation, so that the same construction process can create different representations.
insert image description here
(Image source: https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/builder.html)

The builder pattern usually has two application scenarios:

  1. The steps of object creation are relatively complicated, and multiple steps such as steps 1, 2, and 3 are required to create successfully
  2. The object itself has many attributes, and there may be constraints between the attributes

Let's first look at the first case of creating complex objects.

Making Black Jade Intermittent Paste

The code for making Black Jade Intermittent Ointment is as follows:

Medicines:

/**
 * 药品类
 */
public class Drug {
    
    

    /**
     * 药品名称
     */
    private String name;

    /**
     * 是否已混合
     */
    private boolean isMixed;

    /**
     * 是否已浸泡
     */
    private boolean isSoakd;

    /**
     * 是否已加入秘药
     */
    private boolean hasSecretMedicine;

    /**
     * 是否已炼制
     */
    private boolean isRefine;

    /**
     * 是否已晾晒
     */
    private boolean isDry;

    /**
     * 是否已密封
     */
    private boolean isSeal;

    public Drug(String name) {
    
    
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        StringBuffer display = new StringBuffer();
        display.append("---- 获得 " + name + " 生产情况 ----\n");
        display.append("是否已混合:" + isMixed+ "\n");
        display.append("是否已浸泡:" + isSoakd+ "\n");
        display.append("是否已加入秘药:" + hasSecretMedicine+ "\n");
        display.append("是否已炼制:" + isRefine+ "\n");
        display.append("是否已晾晒:" + isDry+ "\n");
        display.append("是否已密封:" + isSeal+ "\n");
        return display.toString();
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public boolean isMixed() {
    
    
        return isMixed;
    }

    public void setMixed(boolean mixed) {
    
    
        isMixed = mixed;
    }

    public boolean isSoakd() {
    
    
        return isSoakd;
    }

    public void setSoakd(boolean soakd) {
    
    
        isSoakd = soakd;
    }

    public boolean isHasSecretMedicine() {
    
    
        return hasSecretMedicine;
    }

    public void setHasSecretMedicine(boolean hasSecretMedicine) {
    
    
        this.hasSecretMedicine = hasSecretMedicine;
    }

    public boolean isRefine() {
    
    
        return isRefine;
    }

    public void setRefine(boolean refine) {
    
    
        isRefine = refine;
    }

    public boolean isDry() {
    
    
        return isDry;
    }

    public void setDry(boolean dry) {
    
    
        isDry = dry;
    }

    public boolean isSeal() {
    
    
        return isSeal;
    }

    public void setSeal(boolean seal) {
    
    
        isSeal = seal;
    }

}

Drug construction interface:

/**
 * 药品建造接口
 */
public interface DrugBuilder {
    
    

    /**
     * 混合
     */
    public void mix();

    /**
     * 浸泡
     */
    public void soak();

    /**
     * 加入秘药
     */
    public void addSecretMedicine();

    /**
     * 炼制
     */
    public void refine();

    /**
     * 晾晒
     */
    public void dry();

    /**
     * 密封
     */
    public void seal();
}

Black Jade Staccato Paste Builder Class:

/**
 * 黑玉断续膏建造者类
 */
public class HeiYuDuanXuGaoBulider implements DrugBuilder{
    
    

    private Drug drug;

    public HeiYuDuanXuGaoBulider() {
    
    
        this.drug = new Drug("黑玉断续膏");
    }

    /**
     * 混合
     */
    @Override
    public void mix() {
    
    
        this.drug.setMixed(true);
    }

    /**
     * 浸泡
     */
    @Override
    public void soak() {
    
    
        this.drug.setSoakd(true);
    }

    /**
     * 加入秘药
     */
    @Override
    public void addSecretMedicine() {
    
    
        this.drug.setHasSecretMedicine(true);
    }

    /**
     * 炼制
     */
    @Override
    public void refine() {
    
    
        this.drug.setRefine(true);
    }

    /**
     * 晾晒
     */
    @Override
    public void dry() {
    
    
        this.drug.setDry(true);
    }

    /**
     * 密封
     */
    @Override
    public void seal() {
    
    
        this.drug.setSeal(true);
    }

    /**
     * 获取药品
     * @return
     */
    public Drug getResult() {
    
    
        return this.drug;
    }
}

Director class:

/**
 * 导向器类
 */
public class Director {
    
    

    /**
     * 建造药品
     * @param drugBuilder
     */
    public void constructDrug(DrugBuilder drugBuilder) {
    
    
        // 混合
        drugBuilder.mix();
        // 浸泡
        drugBuilder.soak();
        // 加入秘药
        drugBuilder.addSecretMedicine();
        // 炼制
        drugBuilder.refine();
        // 晾晒
        drugBuilder.dry();
        // 密封
        drugBuilder.seal();
    }
}

Client class:

/**
 * 客户端类
 */
public class Demo {
    
    
    public static void main(String[] args) {
    
    
        // 创建导向器类
        Director director = new Director();
        // 创建黑玉断续膏建造者类
        HeiYuDuanXuGaoBulider heiYuDuanXuGaoBulider = new HeiYuDuanXuGaoBulider();
        // 建造药品
        director.constructDrug(heiYuDuanXuGaoBulider);
        // 获取药品
        Drug drug = heiYuDuanXuGaoBulider.getResult();
        System.out.println(drug);
    }
}

operation result:

---- 获得 黑玉断续膏 生产情况 ----
是否已混合:true
是否已浸泡:true
是否已加入秘药:true
是否已炼制:true
是否已晾晒:true
是否已密封:true

DrugBuilder: Defines the method steps required to create a Drug object.

HeiYuDuanXuGaoBulider: implement the interface of DrugBuilder, and implement the interface method according to the characteristics of Heiyu intermittent ointment.

Director: Guidance class, constructing objects using the DrugBuilder interface, and producing drugs step by step according to the steps defined in the interface.

Drug: Indicates the complex object to be constructed, that is, black jade intermittent ointment.

The client only needs to call the constructDrug method of the Director class to create the object. The specific production steps and processes are controlled by the Director class, which is transparent to the client and greatly reduces the burden on the client.

multiple parameters

Recently, some martial arts practitioners reported that they sometimes prepared medicines for internal injuries, but suffered trauma, and the medicines for internal injuries could not be used, and were wasted after the expiry date;

If you prepare medicines for external injuries, and sometimes suffer internal injuries, it will also cause waste;

If you prepare medicines for both internal and external injuries at the same time, it will greatly increase the cost (it is not easy to mix in the rivers and lakes now), and generally you will not suffer from internal and external injuries at the same time (that would be too miserable).

In order to improve the service quality and meet the individual needs of customers, Xiaoshuai's master recently developed a new product, which allows customers to prepare portable alchemy furnaces on the spot to treat internal or external injuries.

The principle is this, the medicine for treating internal injuries and the medicine for treating trauma are actually mostly the same ingredients, only a small part is different, the medicine for treating internal injuries is added with Xianlingcao, and the medicine for treating trauma is added with Dali Pill.

So you only need to grind the fairy grass and Dali pill into powder, pack them into small bags, bring them to the customer, add fairy grass or Dali pill as needed, and then mix them with our special mixing pot.

In order to meet individual needs, we also provide customers with two flavors, sweet and salty!

Having said so much, let's take a look at the code:

Medicines:

/**
 * 药品类
 */
public class Drug {
    
    

    /**
     * 药品名称
     */
    private String name;

    /**
     * 治疗类型(0:治疗内伤;1:治疗外伤)
     */
    private int type;

    /**
     * 口味(1:甜味;2:咸味)
     */
    private int taste;

    /**
     * 药品颗粒尺寸(单位cm)
     */
    private int size;

    /**
     * 数量
     */
    private int num;

	/**
     * 构造方法,通过Builder类的属性来构造对象
     * @param drugBuilder
     */
    public Drug(DrugBuilder drugBuilder) {
    
    
        this.name = drugBuilder.name;
        this.type = drugBuilder.type;
        this.taste = drugBuilder.taste;
        this.size = drugBuilder.size;
        this.num = drugBuilder.num;
    }

    @Override
    public String toString() {
    
    
        StringBuffer display = new StringBuffer();
        display.append("---- 您获得了药品:" + name + " ----\n");
        display.append("能够治疗:" + (type == 0 ? "内伤" : "外伤") + "\n");
        display.append("口味:" + (taste == 0 ? "甜味" : "咸味") + "\n");
        display.append("颗粒尺寸:" + size + "cm\n");
        display.append("数量:" + num + "颗\n");
        return display.toString();
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getType() {
    
    
        return type;
    }

    public void setType(int type) {
    
    
        this.type = type;
    }

    public int getTaste() {
    
    
        return taste;
    }

    public void setTaste(int taste) {
    
    
        this.taste = taste;
    }

    public int getSize() {
    
    
        return size;
    }

    public void setSize(int size) {
    
    
        this.size = size;
    }

    public int getNum() {
    
    
        return num;
    }

    public void setNum(int num) {
    
    
        this.num = num;
    }
}

Pharmaceutical construction class:

public class DrugBuilder {
    
    

    /**
     * 药品名称
     */
    public String name;

    /**
     * 治疗类型(0:治疗内伤;1:治疗外伤)
     */
    public int type;

    /**
     * 口味(1:甜味;2:咸味)
     */
    public int taste;

    /**
     * 药品颗粒尺寸(单位cm)
     */
    public int size;

    /**
     * 数量
     */
    public int num;


    /**
     * 构建药品对象
     * @return
     */
    public Drug build() {
    
    

        if(size < 1 || size > 5) {
    
    
            throw new IllegalArgumentException("药品颗粒尺寸必须在1-5cm之间");
        }

        if(num < 1 || size > 10) {
    
    
            throw new IllegalArgumentException("药品数量必须在1-10之间");
        }

        return new Drug(this);
    }

    /**
     * 设置名称
     * @param name
     * @return
     */
    public DrugBuilder setName(String name) {
    
    
        this.name = name;
        return this;
    }

    /**
     * 设置治疗类型
     * @param type
     * @return
     */
    public DrugBuilder setType(int type) {
    
    
        this.type = type;
        return this;
    }

    /**
     * 设置口味
     * @param taste
     * @return
     */
    public DrugBuilder setTaste(int taste) {
    
    
        this.taste = taste;
        return this;
    }

    /**
     * 设置尺寸
     * @param size
     * @return
     */
    public DrugBuilder setSize(int size) {
    
    
        this.size = size;
        return this;
    }

    /**
     * 设置数量
     * @param num
     * @return
     */
    public DrugBuilder setNum(int num) {
    
    
        this.num = num;
        return this;
    }
}

Client class:

public class Demo {
    
    
    public static void main(String[] args) {
    
    
        Drug drug = new DrugBuilder()
                .setName("大力丸")
                .setType(1)
                .setTaste(0)
                .setSize(2)
                .setNum(10)
                .build();

        System.out.println(drug);
    }
}

output:

---- 您获得了药品:大力丸 ----
能够治疗:外伤
口味:甜味
颗粒尺寸:2cm
数量:10

If the object to be created has many properties, and the properties have constraints, such as the size must be between 1-5cm, and the number must be between 1-10, it is more suitable to use the builder mode, so that the properties of the object and Create separation.

This hides complex object construction details from developers, reduces learning costs, and improves code reusability.

Application of builder mode in JDK source code

Let's take a look at JDK's StringBuilder class. It can be seen from the name that it uses the creator mode. It provides the append() method, opens the construction steps, and finally calls the toString() method to obtain a constructed complete string. The screenshot of the source code is as follows:

insert image description here

insert image description here
insert image description here
An example using StringBuilder:

StringBuilder stringBuilder = new StringBuilder();
String str = stringBuilder
        .append("a")
        .append("b")
        .append("c")
        .toString();

Summarize

The builder mode is mainly applicable to the following application scenarios.

  • The same method, but different order of execution, produces different results.
  • Multiple components, or parts, can be assembled into an object, but the results are not the same.
  • The product class is very complex, or different calling sequences in the product class have different effects.
  • Initializing an object is particularly complicated, with many parameters, and many parameters have default values.

The difference between the builder pattern and the factory pattern

Both the builder pattern and the factory pattern are responsible for creating objects, so what is the difference between them?

The factory pattern is used to create different but related types of objects (a group of subclasses inheriting the same parent class or interface), which type of object is determined by the given parameters, and the factory pattern will return the created object immediately.

The builder mode focuses on how to generate complex objects step by step. By setting different optional parameters, different objects can be created "customized", allowing you to perform some additional construction steps before obtaining the object.

It can be seen that the purpose of the builder pattern and the factory pattern are different.

Advantages of the builder pattern

  • Good encapsulation, separation of construction and representation.
  • Consistent with the Single Responsibility Principle, you can separate the complex construction code from the business logic of the product.
  • Easy to control the details, the builder can gradually refine the creation process without any impact on other modules.

Disadvantages of the builder pattern

  • Multiple classes need to be added, so the overall complexity of the code will increase.
  • If the product changes internally, the builder must also modify it simultaneously, and the later maintenance cost is relatively high.

postscript

After Xiancao Pharmacy launched the portable personalized medicine stove, it has won many praises in the martial arts. Everyone even developed apple, orange, and peach-flavored pills by themselves, setting off an upsurge in making personalized pills. Martial arts people have added a lot of fun to the rivers and lakes.

Guess you like

Origin blog.csdn.net/zhanyd/article/details/116531842