1、概念
将一个复杂的对象的构建与它的表示相分离,使得不同的构建过程可以创建出不同的表示,也叫做生成器模式。
工厂模式强调如何生产一个对象,而建造者模式强调顺序,数量不同,组合生成的对象也就会可能产生不同的对象。
2、Java简化版构造模式
在刚看《设计模式之禅》中对建造者模式的讲解时发现,书中的案例和平常工作中遇到的建造者模式不同,当时看的也有点懵逼,先来看一下在我们经常遇到的建造者模式,比如Android的AlertDialog、Glide、Retrofit等也就是下面讲的Java简化版的建造者模式
举个例子:
一台电脑(Computer)包含设备名称、系统版本、CPU型号等多个参数,并且这些参数定义为可空的,如果要初始化这个对象,需要定义众多的构造方法来满足参数可以为空的情况,这种情况可以使用建造者模式结合链式调用简化实现对象的构建。
(对Java而言也可以通过JavaBean的get、set设置属性值,在Kotlin的话因为kotlin支持默认参数属性,所以构造方法在Kotlin中的使用场景相对弱一些)
public class Computer {
/**
* 设备名称,必选
*/
private final String deviceName;
/**
* 可选参数
*/
private final String cpu;
private final String ram;
private final String deviceId;
private final String productId;
private final String systemType;
public Computer(Builder builder) {
deviceName = builder.getDeviceName();
cpu = builder.getCpu();
ram = builder.getRam();
deviceId = builder.getDeviceId();
productId = builder.getProductId();
systemType = builder.getSystemType();
}
public static class Builder {
private final String deviceName;
private String cpu;
private String ram;
private String deviceId;
private String productId;
private String systemType;
public Builder(String deviceName) {
this.deviceName = deviceName;
}
public Computer build() {
return new Computer(this);
}
public String getDeviceName() {
return deviceName;
}
public String getCpu() {
return cpu;
}
public Builder setCpu(String cpu) {
this.cpu = cpu;
return this;
}
public String getRam() {
return ram;
}
public Builder setRam(String ram) {
this.ram = ram;
return this;
}
public String getDeviceId() {
return deviceId;
}
public Builder setDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
public String getProductId() {
return productId;
}
public Builder setProductId(String productId) {
this.productId = productId;
return this;
}
public String getSystemType() {
return systemType;
}
public Builder setSystemType(String systemType) {
this.systemType = systemType;
return this;
}
}
@Override
public String toString() {
return "主机信息\n" +
"设备名称:" + deviceName + '\n' +
"处理器:" + cpu + '\n' +
"内存:" + ram + '\n' +
"设备ID:" + deviceId + '\n' +
"产品ID:" + productId + '\n' +
"系统类型:" + systemType + '\n';
}
}
如下使用方式
public class Main {
public static void main(String[] args) {
Computer computer = new Computer.Builder("张三的电脑")
.setCpu("Intel(R) Core(TM)i7-10510U CPU1.8Hz~2.3Hz")
.setRam("16GB")
.setDeviceId("AS87AD7C-SDGF-SDDV-7DUY8655SD")
.setProductId("00425-00000-00002-AA474")
.setSystemType("Microsoft Windows 10 企业版 LTSC")
.build();
System.out.println(computer.toString());
}
}
输出结果如下:
主机信息
设备名称:张三的电脑
处理器:Intel(R) Core(TM)i7-10510U CPU1.8Hz~2.3Hz
内存:16GB
设备ID:AS87AD7C-SDGF-SDDV-7DUY8655SD
产品ID:00425-00000-00002-AA474
系统类型:Microsoft Windows 10 企业版 LTSC
3、经典版建造者模式
上面李局了Java简化版的构造者模式,但是经典的构造者模式跟上面这个比起来结构有较大不一致,还是以创建Computer对象为例
3.1、建造者模式创建Computer类图
对于类图中四个成员的定义如下:
- Computer:要创建的产品对象
- Builder:抽象建造者,定义创建产品对象各个子部分的模板方法,定义创建产品对象的方法
- LenovoBuilder:具体的建造者实现类,负责实现产品的各个子部件的实现和最终产品对象的创建
- Director:负责使用Builder角色的接口API来生成产品实例
首先定义最终要生产的产品类如下
public class Computer {
/**
* 设备名称,必选
*/
private final String deviceName;
/**
* 可选参数
*/
private String cpu;
private String ram;
private String deviceId;
private String productId;
private String systemType;
public Computer(String deviceName) {
this.deviceName = deviceName;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getRam() {
return ram;
}
public void setRam(String ram) {
this.ram = ram;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getSystemType() {
return systemType;
}
public void setSystemType(String systemType) {
this.systemType = systemType;
}
@Override
public String toString() {
return "主机信息\n" +
"设备名称:" + deviceName + '\n' +
"处理器:" + cpu + '\n' +
"内存:" + ram + '\n' +
"设备ID:" + deviceId + '\n' +
"产品ID:" + productId + '\n' +
"系统类型:" + systemType + '\n';
}
}
然后定义抽象建造者
public abstract class Builder {
public abstract void setCpu();
public abstract void setRam();
public abstract void setDeviceId();
public abstract void setProductId();
public abstract void setSystemType();
public abstract Computer buildComputer();
}
具体的子类建造者实现类,这里定义的LenovoBuilder用于创建联想电脑,有其他的产品比如苹果电脑也可以增加AppleBuilder等
public class LenovoBuilder extends Builder {
private final Computer computer ;
public LenovoBuilder(String deviceName) {
computer = new Computer(deviceName);
}
@Override
public void setCpu() {
computer.setCpu("Intel(R) Core(TM)i7-10510U CPU1.8Hz~2.3Hz");
}
@Override
public void setRam() {
computer.setRam("16GB");
}
@Override
public void setDeviceId() {
computer.setDeviceId("AS87AD7C-SDGF-SDDV-7DUY8655SD");
}
@Override
public void setProductId() {
computer.setProductId("00425-00000-00002-AA474");
}
@Override
public void setSystemType() {
computer.setSystemType("Microsoft Windows 10 企业版 LTSC");
}
@Override
public Computer buildComputer() {
return computer;
}
}
苹果笔记本的构建类如下
public class AppleBuilder extends Builder {
private final Computer computer ;
public AppleBuilder(String deviceName) {
computer = new Computer(deviceName);
}
@Override
public void setCpu() {
computer.setCpu("Intel(R) Core(TM)i9-10000 CPU2.3Hz~3.3Hz");
}
@Override
public void setRam() {
computer.setRam("32GB");
}
@Override
public void setDeviceId() {
computer.setDeviceId("234SDFBF-RGGD-SDDV-234RSEFSDF");
}
@Override
public void setProductId() {
computer.setProductId("1111-003400-234234-JH898");
}
@Override
public void setSystemType() {
computer.setSystemType("MacOS 16");
}
@Override
public Computer buildComputer() {
return computer;
}
}
通过Director调用Builder的方法来生成产品对象
public class Director {
public void makeComputer(Builder builder) {
builder.setCpu();
builder.setDeviceId();
builder.setProductId();
builder.setRam();
builder.setSystemType();
}
}
最后使用测试场景如下
public class Main {
public static void main(String[] args) {
Director director = new Director();
LenovoBuilder lenovoBuilder=new LenovoBuilder("联想电脑");
director.makeComputer(lenovoBuilder);
System.out.println(lenovoBuilder.buildComputer());
AppleBuilder appleBuilder=new AppleBuilder("苹果电脑");
director.makeComputer(appleBuilder);
System.out.println(appleBuilder.buildComputer());
}
}
输出结果如下
主机信息
设备名称:联想电脑
处理器:Intel(R) Core(TM)i7-10510U CPU1.8Hz~2.3Hz
内存:16GB
设备ID:AS87AD7C-SDGF-SDDV-7DUY8655SD
产品ID:00425-00000-00002-AA474
系统类型:Microsoft Windows 10 企业版 LTSC
主机信息
设备名称:苹果电脑
处理器:Intel(R) Core(TM)i9-10000 CPU2.3Hz~3.3Hz
内存:32GB
设备ID:234SDFBF-RGGD-SDDV-234RSEFSDF
产品ID:1111-003400-234234-JH898
系统类型:MacOS 16
总结:当产品类非常复杂,不同的调度产生不同的结果时,使用建造者模式比较适合。相同的组件或配件都可以装配到一个对象,但是产生的结果又不相同,可以使用建造者模式。