建造者模式,主要用来构建复杂的对象(变量很多的对象)。如台式电脑,它包括主板、内存条、CPU还有机箱等各个部件,而作为用户,一般不关心这些部件是怎么装配的,也几乎不会单独使用某个部件,而是使用组装好了的电脑。所以你只需要给建造者准备好零部件,让建造者给你建造出产品即可。
一般的建造者模式,是使用如下图的方式,一个导演Director持有一个抽象的Builder跑龙套的,Director调用自己的construct()命令跑龙套的建造产品Product,construct()方法中是抽象的Builder在buildPart1()、buildPart2(),导演不指定具体的龙套,只要持有抽象的Builder即可,龙套的buildPart1()就是在组装Product产品的具体参数,因为Builder持有Product对象。
然而以上并不是Builder pattern的最佳实践
如果按上面的套路来,那建造一个类简直要人命啊,不仅要写抽象接口,并且代码不好阅读。因此建造者模式有很多简单的变种,以下才是我认为最好的建造者模式,直接上代码。
Computer这个产品中有一个专业的建造者Builder,Builder有一个方法build可以建造出一个Computer产品,Computer构造方法私有化,只有Builder才能创建。Builder中有多个方法接收外部给的零部件,等零部件集齐,Builder就可以调用build方法建造一台Computer产品了。注意最好不要在Builder的构造方法中new一个Computer,而应该在builder方法中new,因为Builder构造方法执行时,Builder还没接到零部件。
package builder;
/**
* 一台电脑
*/
public class Computer {
private String mainBoard; // 主板
private String memory; // 内存
private String cpu; // cpu
// 构造函数私有化,不能直接new出一台电脑,因为电脑组装很复杂,需要有专业技能的建造者来建造一台电脑
private Computer(String mainBoard, String memory, String cpu){
this.mainBoard = mainBoard;
this.memory = memory;
this.cpu = cpu;
}
// 一般建造者模式为了易维护,都把builder设置为构建产品的内部静态类
public static class Builder{
// 建造者需要的参数跟它所建造的产品一致
private String mainBoard; // 主板
private String memory; // 内存
private String cpu; // cpu
// Builder构造函数不能私有,他需要来接受零部件
public Builder(){
}
// Builder接收到零部件后,存到自己身上,方法都放回Builder自身
public Builder setMainBoard(String mainBoard){
this.mainBoard = mainBoard;
return this;
}
public Builder setMemory(String memory){
this.memory = memory;
return this;
}
public Builder setCpu(String cpu){
this.cpu = cpu;
return this;
}
// 接收了所有零部件以后,就可以build一个产品了
public Computer build(){
// 这里可以是一个复杂的建造Computer的流程,可能有对参数的一些校验,这里就不写了
Computer c = new Computer(this.mainBoard, this.memory, this.cpu);
return c;
}
}
@Override
public String toString() {
return "Computer{" +
"mainBoard='" + mainBoard + '\'' +
", memory='" + memory + '\'' +
", cpu='" + cpu + '\'' +
'}';
}
}
测试一下:
package builder;
public class BuilderMain {
public static void main(String[] args) {
Computer c = new Computer.Builder().setMainBoard("jijia")
.setCpu("Intel i7")
.setMemory("8g").build();
System.out.println(c);
}
}
测试成功,如下:
等等,上面代码看起来是不是也很累,也需要写大量的代码,以下强烈推荐Lombok插件,Idea创建springboot initial时可以把Lombok勾选上即可
使用了Lombok后,代码如下,只要一个@Builder就可以帮你搞定建造者模式。
然后客户端直接调用即可。