建造者模式
概念
把一个复杂的对象的构建过程抽象封装,只保留对象的表示(获取)方法。
例子
构建自行车,需要车架和坐垫等材料,然后中间需要一系列的组建过程,而车架和坐垫又有很多种材料,但是我们可以观察到,即使部件的材料发生了天翻地覆的变化,但组建的过程基本不会发生变化,我们就可以把组建过程封装起来,然后对于不同材料,添加不同的建造者类即可。
自行车
public class Bike {
private String frame;
private String seat;
@Override
public String toString() {
return "Bike{" +
"frame='" + frame + '\'' +
", seat='" + seat + '\'' +
'}';
}
public String getFrame() {
return frame;
}
public void setFrame(String frame) {
this.frame = frame;
}
public String getSeat() {
return seat;
}
public void setSeat(String seat) {
this.seat = seat;
}
}
抽象建造者
public abstract class Builder {
protected Bike bike = new Bike();
public abstract void buildFrame();
public abstract void buildSeat();
public abstract Bike createBike();
}
摩拜单车建造者
public class MobikeBuilder extends Builder{
@Override
public void buildFrame() {
bike.setFrame("铝合金车架");
}
@Override
public void buildSeat() {
bike.setSeat("橡胶坐垫");
}
@Override
public Bike createBike() {
return bike;
}
}
ofo单车建造者
public class OfoBuilder extends Builder {
@Override
public void buildFrame() {
bike.setFrame("碳纤维车架");
}
@Override
public void buildSeat() {
bike.setSeat("真皮坐垫");
}
@Override
public Bike createBike() {
return bike;
}
}
指挥者
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public Bike construct() {
builder.buildFrame();
builder.buildSeat();
return builder.createBike();
}
}
主要测试方法
public class Test {
public static void main(String[] args) {
// Director director = new Director(new OfoBuilder());
Director director = new Director(new MobikeBuilder());
Bike bike = director.construct();
System.out.println(bike);
}
}
优缺点
优点:上面说过,因为组建过程基本一样,所以可以进行封装,如果后期工艺改变,也只需要更改指挥者的代。
缺点:封装了组建的过程,所以如果对于组建过程不一样的话,就不适用了。
使用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
- 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
- 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
模式拓展
大家应该玩过lombok的@Builder吧,他把我们的类变为了建造者模式,可以很方便地构建对象,那么这里我们就来写一个试试。
public class Phone {
private String cpu;
private String memory;
private String mainBoard;
private String screen;
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", memory='" + memory + '\'' +
", mainBoard='" + mainBoard + '\'' +
", screen='" + screen + '\'' +
'}';
}
private Phone(Builder builder) {
this.cpu = builder.cpu;
this.memory = builder.memory;
this.mainBoard = builder.mainBoard;
this.screen = builder.screen;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
public String getMainBoard() {
return mainBoard;
}
public void setMainBoard(String mainBoard) {
this.mainBoard = mainBoard;
}
public String getScreen() {
return screen;
}
public void setScreen(String screen) {
this.screen = screen;
}
public static final class Builder {
private String cpu;
private String memory;
private String mainBoard;
private String screen;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder memory(String memory) {
this.memory = memory;
return this;
}
public Builder mainBoard(String mainBoard) {
this.mainBoard = mainBoard;
return this;
}
public Builder screen(String screen) {
this.screen = screen;
return this;
}
public Phone build() {
return new Phone(this);
}
}
}
测试方法
public static void main(String[] args) {
Phone phone = new Phone.Builder()
.cpu("111")
.mainBoard("222")
.memory("333")
.screen("444")
.build();
System.out.println("phone = " + phone);
}