附链
你也可以在这些平台阅读本文:
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
用户只需指定需要建造的类型就可以得到它们,建造过程及细节不需要知道。
建造者模式注重于方法的调用顺序,而工厂模式注重于创建产品。
四要素
标准建造者模式有四个要素:
- 产品类:既可以是具体的实体类,也可以是抽象类与其具体实现组成。
- 抽象建造者:接口或者抽象类,将具体的实现过程移交给子类。
- 具体建造者:抽象建造者的具体实现类,用于构建产品。
- 指挥者类:调用合适的建造者方法来构建产品。
场景示例
笔者这里以攒电脑为例。攒机需要购买一些配置,例如:CPU、主板、内存条、硬盘、显卡、机箱、电源、显示器等。然后按照自己的需求和喜好将这些配置攒起来组装成电脑,满足自己的个性化需求。当然也会有一些攒机的商家,来帮用户处理攒机的过程。
创建产品类
/**
* @author zhh
* @description 电脑类
* @date 2020-02-11 14:01
*/
public class Computer {
/**
* cpu
*/
private String cpu;
/**
* 主板
*/
private String mainboard;
/**
* 内存
*/
private String memory;
/**
* 硬盘
*/
private String hardDisk;
/**
* 显卡
*/
private String gpu;
/**
* 机箱
*/
private String crate;
/**
* 电源
*/
private String powerSupply;
/**
* 显示器
*/
private String monitor;
// 此处省略getter、setter方法
@Override
public String toString() {
return "Computer{" + "cpu='" + cpu + '\'' + ", mainboard='" + mainboard + '\'' + ", memory='" + memory + '\'' +
", hardDisk='" + hardDisk + '\'' + ", gpu='" + gpu + '\'' + ", crate='" + crate + '\'' +
", powerSupply='" + powerSupply + '\'' + ", monitor='" + monitor + '\'' + '}';
}
}
创建抽象建造者
抽象电脑建造者类中,额外提供一个组装电脑的方法,其返回参数为产品类。
/**
* @author zhh
* @description 抽象电脑建造者类
* @date 2020-02-11 14:32
*/
public abstract class ComputerBuilder {
public abstract void buyCpu(String cpu);
public abstract void buyMainboard(String mainboard);
public abstract void buyMemory(String memory);
public abstract void buyHardDisk(String hardDisk);
public abstract void buyGpu(String gpu);
public abstract void buyCrate(String crate);
public abstract void buyPowerSupply(String powerSupply);
public abstract void buyMonitor(String monitor);
/**
* 组装电脑
*/
public abstract Computer assembleComputer();
}
创建具体建造者
创建具体的建造者类,继承我们的抽象创建者,实现抽象方法。
/**
* @author zhh
* @description 实际的电脑建造者类
* @date 2020-02-11 14:41
*/
public class ComputerActualBuilder extends ComputerBuilder {
private Computer computer = new Computer();
@Override
public void buyCpu(String cpu) {
computer.setCpu(cpu);
}
@Override
public void buyMainboard(String mainboard) {
computer.setMainboard(mainboard);
}
@Override
public void buyMemory(String memory) {
computer.setMemory(memory);
}
@Override
public void buyHardDisk(String hardDisk) {
computer.setHardDisk(hardDisk);
}
@Override
public void buyGpu(String gpu) {
computer.setGpu(gpu);
}
@Override
public void buyCrate(String crate) {
computer.setCrate(crate);
}
@Override
public void buyPowerSupply(String powerSupply) {
computer.setPowerSupply(powerSupply);
}
@Override
public void buyMonitor(String monitor) {
computer.setMonitor(monitor);
}
@Override
public Computer assembleComputer() {
return computer;
}
}
创建指挥者类
攒机商家是我们的指挥者,商家推荐配置供用户购买参考,帮助用户进行组装。
/**
* @author zhh
* @description 商家类
* @date 2020-02-11 14:55
*/
public class Enterprise {
private ComputerBuilder computerBuilder;
public void setComputerBuilder(ComputerBuilder computerBuilder) {
this.computerBuilder = computerBuilder;
}
/**
* 组装电脑
*/
public Computer assembleComputer(String cpu, String mainboard,
String memory, String hardDisk,
String gpu, String crate,
String powerSupply, String monitor) {
computerBuilder.buyCpu(cpu);
computerBuilder.buyMainboard(mainboard);
computerBuilder.buyMemory(memory);
computerBuilder.buyHardDisk(hardDisk);
computerBuilder.buyGpu(gpu);
computerBuilder.buyCrate(crate);
computerBuilder.buyPowerSupply(powerSupply);
computerBuilder.buyMonitor(monitor);
return computerBuilder.assembleComputer();
}
}
测试类及输出
/**
* @author zhh
* @description 测试类
* @date 2020-02-11 15:05
*/
public class Test {
public static void main(String[] args) {
ComputerBuilder computerBuilder = new ComputerActualBuilder();
Enterprise enterprise = new Enterprise();
enterprise.setComputerBuilder(computerBuilder);
Computer computer = enterprise.assembleComputer("Intel 酷睿i7 8700K",
"影驰B360M-M.2",
"影驰GAMER 8GB DDR4 2400",
"希捷Barracuda 1TB 7200转 64MB",
"七彩虹iGame750Ti 烈焰战神U-Twin-2GD5",
"金河田峥嵘Z30",
"航嘉WD600K",
"三星C27F390FHC");
System.out.println(computer);
}
}
测试类的输出结果如下:
Computer{cpu=‘Intel 酷睿i7 8700K’, mainboard=‘影驰B360M-M.2’, memory=‘影驰GAMER 8GB DDR4 2400’, hardDisk=‘希捷Barracuda 1TB 7200转 64MB’, gpu=‘七彩虹iGame750Ti 烈焰战神U-Twin-2GD5’, crate=‘金河田峥嵘Z30’, powerSupply=‘航嘉WD600K’, monitor=‘三星C27F390FHC’}
类结构图
以上示例类的结构图如下所示
我们可以看到我们的 Test
类和抽象建造者 ComputerBuilder
和产品类 Computer
都没有关系,只和指挥者类 Enterprise
、具体的建造者 ComputerActualBuilder
有关。
Test
类创建指挥者类 Enterprise
,指挥者类 Enterprise
通过组合的方式使用 ComputerBuilder
,实际使用 ComputerActualBuilder
创建产品类 Computer
。
示例演进
上述示例建造者的使用方式只是一种标准的使用方式。
我们发现我们的指挥者类并不是必须的。我们可以不需要攒机商家帮忙组装,我们可以自己动手。
下面来进行代码的演进。
调整产品类
这里使用静态内部类,依靠链式调用的方式来调整产品类。
/**
* @author zhh
* @description 电脑类
* @date 2020-02-11 14:01
*/
public class Computer {
/**
* cpu
*/
private String cpu;
/**
* 主板
*/
private String mainboard;
/**
* 内存
*/
private String memory;
/**
* 硬盘
*/
private String hardDisk;
/**
* 显卡
*/
private String gpu;
/**
* 机箱
*/
private String crate;
/**
* 电源
*/
private String powerSupply;
/**
* 显示器
*/
private String monitor;
public Computer(ComputerBuilder computerBuilder) {
this.cpu = computerBuilder.cpu;
this.mainboard = computerBuilder.mainboard;
this.memory = computerBuilder.memory;
this.hardDisk = computerBuilder.hardDisk;
this.gpu = computerBuilder.gpu;
this.crate = computerBuilder.crate;
this.powerSupply = computerBuilder.powerSupply;
this.monitor = computerBuilder.monitor;
}
@Override
public String toString() {
return "Computer{" + "cpu='" + cpu + '\'' + ", mainboard='" + mainboard + '\'' + ", memory='" + memory + '\'' +
", hardDisk='" + hardDisk + '\'' + ", gpu='" + gpu + '\'' + ", crate='" + crate + '\'' +
", powerSupply='" + powerSupply + '\'' + ", monitor='" + monitor + '\'' + '}';
}
/**
* 声明静态内部类
*/
public static class ComputerBuilder {
/**
* cpu
*/
private String cpu;
/**
* 主板
*/
private String mainboard;
/**
* 内存
*/
private String memory;
/**
* 硬盘
*/
private String hardDisk;
/**
* 显卡
*/
private String gpu;
/**
* 机箱
*/
private String crate;
/**
* 电源
*/
private String powerSupply;
/**
* 显示器
*/
private String monitor;
public ComputerBuilder buyCpu(String cpu){
this.cpu = cpu;
return this;
}
public ComputerBuilder buyMainboard(String mainboard){
this.mainboard = mainboard;
return this;
}
public ComputerBuilder buyMemory(String memory){
this.memory = memory;
return this;
}
public ComputerBuilder buyHardDisk(String hardDisk){
this.hardDisk = hardDisk;
return this;
}
public ComputerBuilder buyGpu(String gpu){
this.gpu = gpu;
return this;
}
public ComputerBuilder buyCrate(String crate){
this.crate = crate;
return this;
}
public ComputerBuilder buyPowerSupply(String powerSupply){
this.powerSupply = powerSupply;
return this;
}
public ComputerBuilder buyMonitor(String monitor){
this.monitor = monitor;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
测试类及输出
/**
* @author zhh
* @description 测试类
* @date 2020-02-11 15:05
*/
public class Test {
public static void main(String[] args) {
Computer computer = new Computer.ComputerBuilder()
.buyCpu("Intel 酷睿i7 8700K")
.buyMainboard("影驰B360M-M.2")
.buyMemory("影驰GAMER 8GB DDR4 2400")
.buyHardDisk("希捷Barracuda 1TB 7200转 64MB")
.buyGpu("七彩虹iGame750Ti 烈焰战神U-Twin-2GD5")
.buyCrate("金河田峥嵘Z30")
.buyPowerSupply("航嘉WD600K")
.buyMonitor("三星C27F390FHC")
.build();
System.out.println(computer);
}
}
测试类的输出结果如下:
Computer{cpu=‘Intel 酷睿i7 8700K’, mainboard=‘影驰B360M-M.2’, memory=‘影驰GAMER 8GB DDR4 2400’, hardDisk=‘希捷Barracuda 1TB 7200转 64MB’, gpu=‘七彩虹iGame750Ti 烈焰战神U-Twin-2GD5’, crate=‘金河田峥嵘Z30’, powerSupply=‘航嘉WD600K’, monitor=‘三星C27F390FHC’}
类结构图
以上演进的结构图如下所示
源码中的用例
java.lang.StringBuilder
和java.lang.StringBuffer
Spring
中的BeanDefinitionBuilder
MyBatis
中的SqlSessionFactoryBuilder
总结
适用场景
- 一个对象有非常复杂的内部结构(很多属性)
- 想把复杂对象的创建和使用分离
优点
- 封装性比较好,创建和使用分离
- 扩展性好,建造类之间独立,在一定程度上解耦
缺点
- 会产生多余的Builder对象
- 产品内部结构发生变化,建造者都需要修改,成本比较大
参考
- 《Head First 设计模式》
- 《大话设计模式》
- 维基百科-生成器模式