建造者模式(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;}@Overridepublic 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{@Overridepublic void buildCPU() {computer.setCPU("Intel i9");}@Overridepublic void buildRAM() {computer.setRAM("32GB");}@Overridepublic void buildStorage() {computer.setStorage("1TB SSD");}@Overridepublic Computer build() {return computer;}
}
public class OfficeComputerBuilder implements Builder{@Overridepublic void buildCPU() {computer.setCPU("Intel i5");}@Overridepublic void buildRAM() {computer.setRAM("8GB");}@Overridepublic void buildStorage() {computer.setStorage("500GB HDD");}@Overridepublic 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;}@Overridepublic 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);}
}