Builder pattern learning for Java design patterns

  • 2020-04-01 02:45:03
  • OfStack

1 overview
The Builder Pattern is mainly used to "build a complex object in steps", in which "steps" is a stable algorithm, and the various parts of the complex object are often changed. Therefore, the builder pattern is primarily used to address requirements changes in the "object part." This allows for more fine-grained control over the process of object construction.

Example 2
Take cell phones for example. Each cell phone is divided into Screen, CPU and Battery. There are now two phones to be made, the MAC and samsung.

  Apple:

 


 package org.scott.builder.before.use;
import java.util.ArrayList;
import java.util.List;

public class ApplePhone {
    List<String> parts = new ArrayList<String>();

    public void createCPU() {
        parts.add("CUP: Qualcomm");
    }
    public void createScreen() {
        parts.add("SCREEN: JDI");
    }

    public void createBattery() {
        parts.add("BATTERY: DeSai");
    }

    public void show(){
        System.out.print(" Product component information: ");
        for(String part : parts){
            System.out.print(part + "t");
        }
    }
}
 

  Samsung:

 


 package org.scott.builder.before.use;
import java.util.ArrayList;
import java.util.List;

public class SamsungPhone {
    List<String> parts = new ArrayList<String>();

    public void createCPU() {
        parts.add("CUP: MTK");
    }
    public void createScreen() {
        parts.add("SCREEN: Samsung");
    }

    public void createBattery() {
        parts.add("BATTERY: DeSai");
    }

    public void show(){
        System.out.print(" Product component information: ");
        for(String part : parts){
            System.out.print(part + "t");
        }
    }
}
 

Test client:


package org.scott.builder.before.use;

public class BuilerTest {
    private static ApplePhone iphone = new ApplePhone();
    private static SamsungPhone samPhone = new SamsungPhone();

    public static void main(String args[]){
        iphone.createCPU();
        iphone.createScreen();
        iphone.createBattery();
        iphone.show();

        samPhone.createCPU();
        samPhone.createScreen();
        samPhone.createBattery();
        samPhone.show();
    }
}

Did you find a problem? That is in the production of mobile phone every working procedure is the same, process name, actually, only the specific processing is different, each working procedure process is the same, just a few steps, the process of each working procedure is changing, as a result, we can use the same extracted, with changeless should change ", will change, and to the specific products to do.
How exactly? This time the Builder mode comes in handy.

First, a Phone interface:


package org.scott.builder.after.use;
import java.util.ArrayList;
import java.util.List;

public abstract class Phone {
    protected List<String> parts = new ArrayList<String>();

    public void add(String part){
        parts.add(part);
    }
    public void show(){
        System.out.print(" Product component information: ");
        for(String part : parts){
            System.out.print(part + "t");
        }
    }
}

Iphone:


package org.scott.builder.after.use;

public class ApplePhone extends Phone{
}

Samsung mobile phone:


package org.scott.builder.after.use;

public class SamsungPhone extends Phone{
}

Re-define the interface Builder for each production step:


package org.scott.builder.after.use;

public interface Builder {
    public void buildCPU();

    public void buildScreen();

    public void buildBattery();

    public Phone getPhone();
}

Builder for iphone:


package org.scott.builder.after.use;

public class ApplePhoneBuilder implements Builder{
    private Phone phone = new ApplePhone();

    @Override
    public void buildCPU() {
        phone.add("CUP: Qualcomm");
    }
    @Override
    public void buildScreen() {
        phone.add("SCREEN: JDI");
    }
    @Override
    public void buildBattery() {
        phone.add("BATTERY: DeSai");
    }
    @Override
    public Phone getPhone() {
        return phone;
    }
}

Builder for samsung phones:


package org.scott.builder.after.use;

public class SamsungPhoneBuilder implements Builder{

    private Phone phone = new SamsungPhone();

    @Override
    public void buildCPU() {
        phone.add("CUP: MTK");        
    }
    @Override
    public void buildScreen() {
        phone.add("SCREEN: Samsung");
    }
    @Override
    public void buildBattery() {
        phone.add("BATTERY: DeSai");        
    }
    @Override
    public Phone getPhone() {
        return phone;
    }
}

Director for specific production of mobile phones:


package org.scott.builder.after.use;

public class Director {
    private Builder builder;

    public Director(Builder builder){
        this.builder = builder;
    }

    public void construct(){
        builder.buildCPU();
        builder.buildScreen();
        builder.buildBattery();
    }
}

Finally, write a test class:


package org.scott.builder.after.use;

public class BuilderTest {
    private static Builder iPhoneBuilder = new ApplePhoneBuilder();
    private static Builder samPhoneBuilder  = new SamsungPhoneBuilder();

    public static void main(String[] args) {
        Director director = new Director(iPhoneBuilder);
        director.construct();
        Phone phone = iPhoneBuilder.getPhone();
        System.out.println("iphone");
        phone.show();

        director = new Director(samPhoneBuilder);
        director.construct();
        phone = samPhoneBuilder.getPhone();
        System.out.println("nsamSung");
        phone.show();
    }
}

Operation results:


iphone
 Product component information: CUP: Qualcomm    SCREEN: JDI    BATTERY: DeSai    
samSung
 Product component information: CUP: MTK    SCREEN: Samsung    BATTERY: DeSai 

The two Phone entity classes here are empty. If this is the case, they can be omitted, and if the Phone interface can be omitted, all that is left is Director, Builder, and the concrete Bulider implementation classes. In addition, ApplePhone class and SamsungPhone class are related two classes, they are different Phone brands, if encountered two or more classes without too much relationship, the public interface Phone is not necessary to exist, but at this time, then the Builder interface of the specified getPhone() method return value how to determine?

Regardless of whether the return value type is ApplePhone or SamsungPhone, this can cause problems because the return result type is not uniform. At this point, you can define the Phone as an empty interface (an interface that does not contain any methods), and then let these concrete product classes that are not related to each other to implement this interface, then the return value type of getPhone() method specified in the Builder interface is still the type of Phone, then the problem is solved. In this case, however, there is no need to use Builder mode.


Related articles: