builder desigin pattern
建造者模式的概念、建造者模式的结构、建造者模式的优缺点、建造者模式的使用场景、建造者模式的实现示例、建造者模式的源码分析
1、建造者模式的概念
将一个复杂对象的构建和表示分离,使得同样的创建过程可以得到不同的表示。其主要特点是将产品本身和产品创建过程解耦,且分解产品创建过程,使创建过程更加清晰,同时也方便控制产品的创建过程步骤。
2、建造者模式的结构
- 产品:包含多个简单部分的复杂对象,由具体建造者负责创建各个简单部分。
- 抽象建造者:定义了创建各个简单部分和返回复杂产品对象的抽象方法。
- 具体建造者:实现抽象建造者,实现产品简单部分的具体创建。
- 指挥者:调用建造者创建产品简单部分的方法来创建产品简单部分,然后调用建造者返回复杂产品对象的方法生成最终结果。在指挥者中不设计具体产品信息。

3、建造者模式的优缺点
- 优点: 
  - 产品本身和创建过程解耦,使得相同的创建过程可以创建出不同的产品对象。
- 每一个具体建造者都相对独立,与其它具体建造者无关,即若有新的具体建造者加入时不必修改原有的代码,满足开闭原则。
- 更加精细的控制产品的创建过程。将复杂对象的创建分解成多个简单创建的步骤,使得创建过程更加清晰,同时也方便通过程序来控制产品的创建过程。
 
- 缺点: 
  - 使用范围一定程度受限。建造者模式所创建的产品一般具有较多共同点,如果产品之间差异较大则不适用。
- 如果产品的内部变化复杂,则可能需要定义多个具体建造者来实现这种变化,这将会导致代码臃肿,降低代码可读性。
 
4、建造者模式的使用场景
- 创建的对象较复杂,由多个组件构成,且各组件面临着复杂的变化,但组件间的构建顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终表示是独立的。
5、建造者模式的实现示例
复杂产品:
public class Product {
    private String partA;   // 产品的部分 A
    private String partB;   // 产品的部分 B
    private String partC;   // 产品的部分 C
    public String getPartA() {
        return partA;
    }
    public void setPartA(String partA) {
        this.partA = partA;
    }
    public String getPartB() {
        return partB;
    }
    public void setPartB(String partB) {
        this.partB = partB;
    }
    public String getPartC() {
        return partC;
    }
    public void setPartC(String partC) {
        this.partC = partC;
    }
    @Override
    public String toString() {
        return "Product{" +
                "partA='" + partA + '\'' +
                ", partB='" + partB + '\'' +
                ", partC='" + partC + '\'' +
                '}';
    }
}
抽象构建者:
public abstract class Builder {
    protected Product product = new Product();   // 产品实例
    public abstract void buildPartA();   // 构建产品的部分 A
    public abstract void buildPartB();   // 构建产品的部分 B
    public abstract void buildPartC();   // 构建产品的部分 C
    /**
     * 返回产品实例
     * @return
     */
    public Product builder() {
        return product;
    }
}
具体构建者一:
public class OneBuilder extends Builder {
    @Override
    public void buildPartA() {
        product.setPartA("一的部分 a");
    }
    @Override
    public void buildPartB() {
        product.setPartB("一的部分 b");
    }
    @Override
    public void buildPartC() {
        product.setPartC("一的部分 c");
    }
}
具体构建者二:
public class TwoBuilder extends Builder {
    @Override
    public void buildPartA() {
        product.setPartA("二的部分 a");
    }
    @Override
    public void buildPartB() {
        product.setPartB("二的部分 b");
    }
    @Override
    public void buildPartC() {
        product.setPartC("二的部分 c");
    }
}
指挥者:
public class Director {
    private Builder builder;
    public Director(Builder builder) {
        this.builder = builder;
    }
    public void setBuilder(Builder builder) {
        this.builder = builder;
    }
    /**
     * 按照产品的构建步骤构建产品
     * @return
     */
    public Product buildProduct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.builder();
    }
}
测试:
public class BuilderTest {
    public static void main(String[] args) {
        Builder oneBuilder = new OneBuilder();
        Builder twoBuilder = new TwoBuilder();
        Director director = new Director(oneBuilder);
        Product oneProduct = director.buildProduct();
        director.setBuilder(twoBuilder);
        Product twoProduct = director.buildProduct();
        System.out.println(oneProduct);
        System.out.println(twoProduct);
    }
}
测试结果:
Product{partA='一的部分 a', partB='一的部分 b', partC='一的部分 c'}
Product{partA='二的部分 a', partB='二的部分 b', partC='二的部分 c'}
6、建造者模式的源码分析
建造者模式出上述用途外,其在在 jdk、spring 等源码中以及日常开发中最常用的另外一种方式则是:当一个构造器需要传入很多参数时,其代码可读性会较差,且很容易引入错误,此时就可以利用建造者模式。
public class Three {
    private String partA;
    private String partB;
    private String partC;
    public Three(Builder builder) {
        this.partA = builder.partA;
        this.partB = builder.partB;
        this.partC = builder.partC;
    }
    public static class Builder {
        private String partA;
        private String partB;
        private String partC;
        public Builder() {}
        public Builder partA(String partA) {
            this.partA = partA;
            return this;
        }
        public Builder partB(String partB) {
            this.partB = partB;
            return this;
        }
        public Builder partC(String partC) {
            this.partC = partC;
            return this;
        }
        public Three build() {
            return new Three(this);
        }
    }
}
Three three = new Three.Builder()
                .partA("a")
                .partB("b")
                .partC("v")
                .build();


















