建造者模式(Builder Pattern)是一种创建型设计模式,旨在将一个复杂对象的构建过程与其表示分离。它允许通过一步步地构造对象,而不需要暴露对象的内部细节和构建过程。通常,这个模式适用于创建对象时需要多个步骤,而这些步骤是独立于对象类型的。
建造者模式的核心思想是:将复杂对象的创建过程分解成多个简单的步骤,并通过一个“建造者”来逐步构建这些步骤,从而得到最终的复杂对象。这个模式特别适合于需要动态创建不同类型的对象,且这些对象的构建过程可能涉及多个变化和不同的配置选项。
1. 建造者模式的结构
建造者模式通常由以下几个角色组成:
-
Product(产品类):表示复杂对象的最终表示。建造者模式的目的是将这个复杂对象的创建过程封装起来,最终生成一个完整的产品。
-
Builder(建造者):声明构建产品的抽象步骤,通常是一个接口或抽象类,定义了构建产品的各种部件的方法。
-
ConcreteBuilder(具体建造者):实现了
Builder
接口,完成具体的构建过程。每个具体建造者都负责一步步地构建一个产品实例,并且在最终返回产品时,会把各个部件组合成一个完整的对象。 -
Director(指挥者):负责指挥
Builder
的构建过程,按照特定的顺序调用Builder
中的构建步骤。Director
类不参与产品的具体构建工作,它只关心构建的顺序和流程。 -
Client(客户端):通过
Director
来控制建造过程,最终得到复杂的产品对象。
2. 建造者模式的实现
2.1 例子:建造一个复杂的 Computer
对象
假设我们要创建一个 Computer
对象,该对象包含多个部件:处理器(CPU)、内存(RAM)、硬盘(Storage)等。每个部件的配置可以不同,并且它们的创建过程可能较为复杂。在这种情况下,建造者模式可以帮助我们一步步构建这个对象。
2.2 代码实现
- 产品类
public class Computer {
private String CPU;
private String RAM;
private String Storage;
public void setCPU(String CPU) {
this.CPU = CPU;
}
public void setRAM(String RAM) {
this.RAM = RAM;
}
public void setStorage(String Storage) {
this.Storage = Storage;
}
@Override
public String toString() {
return "Computer [CPU=" + CPU + ", RAM=" + RAM + ", Storage=" + Storage + "]";
}
}
- 建造者接口
public interface Builder {
Computer computer = new Computer();
void buildCPU();
void buildRAM();
void buildStorage();
public Computer build();
}
- 具体建造者类
public class GamingComputerBuilder implements Builder{
@Override
public void buildCPU() {
computer.setCPU("Intel i9");
}
@Override
public void buildRAM() {
computer.setRAM("32GB");
}
@Override
public void buildStorage() {
computer.setStorage("1TB SSD");
}
@Override
public Computer build() {
return computer;
}
}
public class OfficeComputerBuilder implements Builder{
@Override
public void buildCPU() {
computer.setCPU("Intel i5");
}
@Override
public void buildRAM() {
computer.setRAM("8GB");
}
@Override
public void buildStorage() {
computer.setStorage("500GB HDD");
}
@Override
public Computer build() {
return computer;
}
}
- 指挥者类
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public Computer construct(){
builder.buildCPU();
builder.buildRAM();
builder.buildStorage();
return builder.build();
}
}
- 测试程序
public class Client {
public static void main(String[] args) {
//通过选择不同的构造器,实现不同产品的构筑
// Director director = new Director(new GamingComputerBuilder());
Director director = new Director(new OfficeComputerBuilder());
Computer computer = director.construct();
System.out.println(computer);
}
}
2.3 运行结果
在这个示例中:
Computer
类是复杂对象,它由多个部件(如 CPU、RAM、Storage)组成。Builder
是构建Computer
的抽象接口,定义了如何构建不同的部件。GamingComputerBuilder
和OfficeComputerBuilder
是Builder
接口的具体实现,负责创建不同配置的Computer
对象。Director
负责指挥构建过程,它会调用Builder
中的方法按特定的顺序构建Computer
。- 最终,客户端通过
Director
获取到构建好的Computer
对象。
3. 建造者模式的优缺点
优点:
-
分离了复杂对象的构建与表示:客户端只需要了解
Director
和Builder
,而不需要关心构建的细节。 -
灵活性高:可以通过不同的
Builder
实现类,灵活地创建各种配置的对象,满足不同需求。 -
可读性强:每一步构建操作都明确地分开了,避免了将所有构建步骤堆叠在一起的情况,从而提高了代码的可读性和可维护性。
-
支持增量构建:每个建造者都可以支持增量构建,客户端可以控制每个构建步骤的细节,甚至动态调整对象的构建过程。
缺点:
-
类的数量增加:为了实现建造者模式,通常会需要多个
Builder
类及Director
类,这会导致类的数量增多,增加了系统的复杂度。 -
不适合所有情况:如果对象的构建非常简单,或者构建过程并不复杂,使用建造者模式可能显得过于复杂和冗余。
-
无法动态调整构建步骤:建造者模式通常在编译时就确定了构建的步骤顺序,因此它对动态调整和灵活变化的需求支持较差。
4. 应用场景
建造者模式适合以下场景:
-
对象构建过程复杂且有多个部分:例如,创建一个复杂的产品或对象,该对象由多个部件或配置组成。
-
需要构建不同表示的产品:当你需要构建不同的产品(例如,游戏电脑和办公电脑),这些产品具有相同的构建步骤,但部件的配置不同。
-
产品的构建过程独立于产品的具体类:如果你希望产品的构建过程与产品的具体类型分开,这时建造者模式非常适用。
5.建造者模式拓展
除了上述使用方式外,建造者模式在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果直接创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。
手机类重构示例
- 手机类
package com.tian.pattern.builder.demo2;
public class Phone {
private String cpu;
private String screen;
private String memory;
private String mainboard;
//私有构造方法
private Phone(Builder builder) {
this.cpu = builder.cpu;
this.screen = builder.screen;
this.memory = builder.memory;
this.mainboard = builder.mainboard;
}
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainboard='" + mainboard + '\'' +
'}';
}
public static final class Builder {
private String cpu;
private String screen;
private String memory;
private String mainboard;
public Builder cpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder screen(String screen) {
this.screen = screen;
return this;
}
public Builder memory(String memory) {
this.memory = memory;
return this;
}
public Builder mainboard(String mainboard) {
this.mainboard = mainboard;
return this;
}
//使用构建者创建Phone对象
public Phone build() {
return new Phone(this);
}
}
}
- 测试类
public class Client {
public static void main(String[] args) {
Phone phone = new Phone.Builder()
.setCpu("intel")
.setScreen("三星屏幕")
.setMemory("金士顿内存条")
.setMainboard("华硕主板")
.build();
System.out.println(phone);
}
}