3_建造者模式
简述:建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
也就是说不仅仅是关注 new 对象的结果,更注重对象属性的赋值过程!
实体类 #:
public class Computer {
private String cpu;
private String gpu;
private String memory;
private String Hd;
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getGpu() {
return gpu;
}
public void setGpu(String gpu) {
this.gpu = gpu;
}
public String getHd() {
return Hd;
}
public void setHd(String hd) {
Hd = hd;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", gpu='" + gpu + '\'' +
", memory='" + memory + '\'' +
", Hd='" + Hd + '\'' +
'}';
}
}
反例 #1 :
现在开始创建对象 。
public class Negative {
public static void main(String[] args) {
Computer computer1 = new Computer();
computer1.setCpu("9700k");
computer1.setGpu("gtx2080ti");
computer1.setMemory("16g");
computer1.setHd("机械1T");
Computer computer2 = new Computer();
computer2.setCpu("9600k");
computer2.setGpu("gtx1080ti");
computer2.setMemory("32g");
computer2.setHd("固态500G");
System.out.println(computer1);
System.out.println(computer2);
}
}
缺陷: 建造复杂对象的时候,客户端程序要炸,造成客户端代码臃肿,且违反迪米特法则(最少知道原则) 。
反例 #2:
将属性赋值过程使用一个建造类封装起来,但此时仍然还不是建造者模式 。
public class Negative2 {
/*=============服务端==========================*/
static class HighComputerBuilder {
private Computer computer = new Computer();
public Computer build() {
computer.setCpu("9700k");
computer.setGpu("gtx2080ti");
computer.setHd("固态1T");
computer.setMemory("32G");
return computer;
}
}
static class MiddleComputerBuilder {
private Computer computer = new Computer();
public Computer build() {
computer.setCpu("9600k");
computer.setGpu("gtx1080ti");
computer.setHd("固态500G");
computer.setMemory("16G");
return computer;
}
}
/*=====================客户端===============================*/
public static void main(String[] args) {
HighComputerBuilder builder1 = new HighComputerBuilder();
Computer computer1 =builder1.build();
MiddleComputerBuilder builder2 = new MiddleComputerBuilder();
Computer computer2 =builder2.build();
System.out.println(computer1);
System.out.println(computer2);
}
}
UML
类图如下:
缺陷:建造者遗漏部分建造步骤,编译也会通过,会造成建造出来的对象不符合要求。比如,漏执行某一步骤时,使得部分值为 null ,后续对象属性被调用时,可能会抛出空指针NullPointerException
异常,会造成程序崩溃。
反例 #3:
定义一个建造者接口来进行规范 。
public class Negative3 {
/*=============服务端==========================*/
/***定义一个建造者接口进行规范****/
interface ComputerBuilder{
Computer build();
void setCpu();
void setGpu();
void setMemory();
void setHd();
}
static class HighComputerBuilder implements ComputerBuilder{
private Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("9700k");
}
@Override
public void setGpu() {
computer.setGpu("gtx2080ti");
}
@Override
public void setMemory() {
computer.setMemory("32G");
}
@Override
public void setHd() {
computer.setHd("固态1T");
}
@Override
public Computer build() {
return computer;
}
}
static class MiddleComputerBuilder implements ComputerBuilder{
private Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("9500k");
}
@Override
public void setGpu() {
computer.setGpu("gtx1060ti");
}
@Override
public void setMemory() {
computer.setMemory("16G");
}
@Override
public void setHd() {
computer.setHd("固态500G");
}
@Override
public Computer build() {
return computer;
}
}
/*==============客户端=====================================*/
public static void main(String[] args) {
HighComputerBuilder builder1 = new HighComputerBuilder();
builder1.setCpu();
builder1.setGpu();
builder1.setHd();
builder1.setMemory();
Computer computer1 =builder1.build();
MiddleComputerBuilder builder2 = new MiddleComputerBuilder();
builder2.setCpu();
builder2.setGpu();
builder2.setHd();
builder2.setMemory();
Computer computer2 =builder2.build();
System.out.println(computer1);
System.out.println(computer2);
}
}
创造了建造者接口,创建者不会再遗漏步骤。
UML
类图如下:
缺陷:
- 每一个
builder
都要自己去调用setXXX
方法进行创建,造成代码重复。 - 需要客户端自己执行创建步骤,建造复杂对象的时候,容易造成客户端代码臃肿,且违反迪米特法则(最少知道原则)。而且客户端会出现遗漏步骤的情况。感觉又回到了原点 。
正例 #1:
将属性赋值步骤,交给一个指挥者,让它去指挥建造者完成,我们只需要安排指挥者就行 。
public class Negative3 {
/*=============服务端==========================*/
interface ComputerBuilder {
Computer build();
void setCpu();
void setGpu();
void setMemory();
void setHd();
}
static class HighComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("9700k");
}
@Override
public void setGpu() {
computer.setGpu("gtx2080ti");
}
@Override
public void setMemory() {
computer.setMemory("32G");
}
@Override
public void setHd() {
computer.setHd("固态1T");
}
@Override
public Computer build() {
return computer;
}
}
static class MiddleComputerBuilder implements ComputerBuilder {
private Computer computer = new Computer();
@Override
public void setCpu() {
computer.setCpu("9500k");
}
@Override
public void setGpu() {
computer.setGpu("gtx1060ti");
}
@Override
public void setMemory() {
computer.setMemory("16G");
}
@Override
public void setHd() {
computer.setHd("固态500G");
}
@Override
public Computer build() {
return computer;
}
}
//--------------指挥者---------------//
static class Director {
public Computer build(ComputerBuilder builder) {
builder.setCpu();
builder.setGpu();
builder.setMemory();
builder.setHd();
return builder.build();
}
}
/*==============客户端=====================================*/
public static void main(String[] args) {
HighComputerBuilder hcb = new HighComputerBuilder();
MiddleComputerBuilder mcb = new MiddleComputerBuilder();
Director director = new Director();
Computer computer1 = director.build(hcb);
Computer computer2 = director.build(mcb);
System.out.println(computer1);
System.out.println(computer2);
}
}
UML
类图如下:
此时在需要增加一个不同配置的 LowComputer 类型计算机,只需要编写一个LowComputerBuilder
类实现 ComputerBuilder 接口,再传给指挥者 Director 进行创建即可得到一个 LowComputer 类型的 Computer 对象。符合开闭原则 。
总结一下建造者模式的优点:
- 创建对象的过程保持稳定。(通过 ComputerBuilder 接口保持稳定)
- 创建过程只需要编写一次(通过实现 ComputerBuilder 接口的类保持稳定)
- 保持扩展性,需要创建新类型的对象时,只需要创建新的 Builder ,再使用指挥者 Director 进行调用进行创建即可。
- 增加指挥者 Director 保证步骤稳定执行,客户端不需要知道创建对象的具体步骤,符合迪米特法则(最少知道原则)。
建造者模式和工厂模式的区别
- 工厂模式注重
new
一个对象就可以,是否得到了这一对象,更多地关注new
的结果。 - 建造者模式注重保证
new
的对象稳定可用,保证不出现细节缺漏,更多关注new
的细节、过程。