建造者模式(Builder Pattern)
创建者模式又叫建造者模式属于创建型模式。
使用同样的构建过程,根据需要创建不同的表示。这种设计模式隐藏了具体的创建过程,将复杂对象的创建过程加以抽象,动态的创建对象。它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
使用
Java实现
建造者中先创建对象
public class ProductCreateBeforeParam {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
//显示产品的特性
System.out.println(toString());
}
@Override
public String toString() {
return "Product{" +
"partA='" + partA + '\'' +
", partB='" + partB + '\'' +
", partC='" + partC + '\'' +
'}';
}
static abstract class Builder {
//创建产品对象
protected ProductCreateBeforeParam productCreateBeforeParam = new ProductCreateBeforeParam();
public abstract Builder buildPartA();
public abstract Builder buildPartB();
public abstract Builder buildPartC();
//返回产品对象
public ProductCreateBeforeParam getResult() {
return productCreateBeforeParam;
}
}
static class Concrete2Builder extends Builder {
@Override
public Builder buildPartA() {
System.out.println("Concrete2建造 PartA");
productCreateBeforeParam.setPartA("Concrete2建造的PartA");
return this;
}
@Override
public Builder buildPartB() {
System.out.println("Concrete2建造 PartB");
productCreateBeforeParam.setPartB("Concrete2建造的PartB");
return this;
}
@Override
public Builder buildPartC() {
System.out.println("Concrete2建造 PartC");
productCreateBeforeParam.setPartC("Concrete2建造的PartC");
return this;
}
}
static class ConcreteBuilder extends Builder {
@Override
public Builder buildPartA() {
System.out.println("Concrete建造 PartA");
productCreateBeforeParam.setPartA("Concrete建造的PartA");
return this;
}
@Override
public Builder buildPartB() {
System.out.println("Concrete建造 PartB");
productCreateBeforeParam.setPartB("Concrete建造的PartB");
return this;
}
@Override
public Builder buildPartC() {
System.out.println("Concrete建造 PartC");
productCreateBeforeParam.setPartC("Concrete建造的PartC");
return this;
}
}
public static void main(String[] args) {
ProductCreateBeforeParam.ConcreteBuilder builder = new ProductCreateBeforeParam.ConcreteBuilder();
builder
.buildPartA()
.buildPartB()
.buildPartC()
.getResult()
.show();
}
}
*****注重创建过程中对于产品的操作
建造者后创建对象
/**
* @author advancer
*/
public class ProductCreateByParam {
private final String partA;
private String partB;
private String partC;
public ProductCreateByParam(Builder builder) {
this.partA = builder.partA;
this.partB = builder.partB;
this.partC = builder.partC;
}
public void show() {
//显示产品的特性
System.out.println(this);
}
public static Builder builder() {
return new Builder("default");
}
@Override
public String toString() {
return "Product{" +
"partA='" + partA + '\'' +
", partB='" + partB + '\'' +
", partC='" + partC + '\'' +
'}';
}
static class Builder {
private final String partA;
private String partB;
private String partC;
public Builder(String partA) {
this.partA = partA;
}
public Builder partB(String partB) {
this.partB = partB;
return this;
}
public Builder partC(String partC) {
this.partC = partC;
return this;
}
//构建产品对象
public ProductCreateByParam build() {
return new ProductCreateByParam(this);
}
}
public static void main(String[] args) {
ProductCreateByParam.builder()
.partB("创建参数PartB")
.partC("创建参数PartC")
.build()
.show();
}
}
*****注重创建过程中对于产品的参数构建
介绍
UML
- Product是产品类。
- Director为指挥者,使用Builder开始建造;
- Builder是抽象建造者,规范产品的组建,一般由子类实现;
- ConcreteBuilder是具体建造者,实现抽象类定义的所有方法,并且返回一个组建好的对象;
- 对应上述代码建造者中先创建对象
作用:
- 在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
- 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:
- 方便创建一个复杂对象的工作,其通常由各个部分的子对象用一定的算法构成,而无需知道算法实现过程。
- 由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
解决原理:
- 创建者模式隐藏了复杂对象的创建过程
- 将负责对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
- 把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
优缺点
优点:
- 建造者独立,易扩展。
- 便于控制细节风险。
缺点:
- 产品必须有共同点,范围有限制。
- 2、如内部变化复杂,会有很多的建造类。
使用场景
场景适用分析:
-
适用
-
需要生成的对象具有复杂的内部结构。
-
需要生成的对象内部属性本身相互依赖。
-
多个部件装配到一个对象中,但产生的运行结果不相同。
-
需要生成的产品对象有复杂的内部结构,这些产品对象具备共性。
-
-
不适用
-
Builder模式不适合创建差异性很大的产品类。
-
产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本。
-
何时使用
- 一些基本结构不会变,而其组合经常变化的时候
- 一个类有很多属性,必须创建对象的时候初始化,如果利用构造函数初始化这些属性,那构造函数回很长,太多参数也不利于使用,容易出错,但是放到set方法中,又不能保证属性的必须初始化;
- 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。
- 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。
实例
-
去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。
-
JAVA 中的
StringBuilder
public StringBuilder append(String str) {...}//apend(String str)等方法便是建造的过程
-
Lombok
中的注解@Builder
自动生成的创建者模式。//Before: @Builder class Example<T> { private T foo; private final String bar; } //After: class Example<T> { private T foo; private final String bar; private Example(T foo, String bar) { this.foo = foo; this.bar = bar; } public static <T> ExampleBuilder<T> builder() { return new ExampleBuilder<T>(); } public static class ExampleBuilder<T> { private T foo; private String bar; private ExampleBuilder() {} public ExampleBuilder foo(T foo) { this.foo = foo; return this; } public ExampleBuilder bar(String bar) { this.bar = bar; return this; } @java.lang.Override public String toString() { return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")"; } public Example build() { return new Example(foo, bar); } } }
注意事项:
与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
与工厂模式的区别:
- 建造者模式更加关注创建时的逻辑。
@Override public String toString() {
return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";
}
public Example build() {
return new Example(foo, bar);
}
}
}
注意事项:
与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。
与工厂模式的区别:
- 建造者模式更加关注创建时的逻辑。
- 工厂模式更加关注创建的对象不同。