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();