提问:通过对比使用构建者模式和不使用构建者模式,以更好的说明构建者模式的作用
GPT:当然,我很乐意通过对比来帮助您更好地理解构建者模式的作用。让我们以一个复杂对象的创建为例,比如一个计算机(Computer)对象,它有多个可配置的部件。
不使用构建者模式
首先,让我们看看不使用构建者模式时,我们如何创建一个 Computer 对象:
public class Computer {
private String CPU;
private String RAM;
private String storage;
private String GPU;
private String operatingSystem;
// 构造函数
public Computer(String CPU, String RAM, String storage, String GPU, String operatingSystem) {
this.CPU = CPU;
this.RAM = RAM;
this.storage = storage;
this.GPU = GPU;
this.operatingSystem = operatingSystem;
}
// Getters...
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Computer computer = new Computer("Intel i7", "16GB", "512GB SSD", "NVIDIA RTX 3070", "Windows 10");
}
}
问题:
- 构造函数参数过多,可读性差。
- 如果某些参数是可选的,需要创建多个构造函数或使用setter方法。
- 参数的顺序很重要,容易出错。
- 如果要添加新的属性,需要修改构造函数,这违反了开闭原则。
使用构建者模式
现在,让我们看看使用构建者模式如何改进这个情况:
public class Computer {
private String CPU;
private String RAM;
private String storage;
private String GPU;
private String operatingSystem;
private Computer(Builder builder) {
this.CPU = builder.CPU;
this.RAM = builder.RAM;
this.storage = builder.storage;
this.GPU = builder.GPU;
this.operatingSystem = builder.operatingSystem;
}
// Getters...
public static class Builder {
private String CPU;
private String RAM;
private String storage;
private String GPU;
private String operatingSystem;
public Builder CPU(String CPU) {
this.CPU = CPU;
return this;
}
public Builder RAM(String RAM) {
this.RAM = RAM;
return this;
}
public Builder storage(String storage) {
this.storage = storage;
return this;
}
public Builder GPU(String GPU) {
this.GPU = GPU;
return this;
}
public Builder operatingSystem(String operatingSystem) {
this.operatingSystem = operatingSystem;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Computer computer = new Computer.Builder()
.CPU("Intel i7")
.RAM("16GB")
.storage("512GB SSD")
.GPU("NVIDIA RTX 3070")
.operatingSystem("Windows 10")
.build();
}
}
优势:
- 可读性提高:每个参数的含义都很清晰。
- 灵活性增强:可以只设置需要的参数,其他参数可以有默认值。
- 参数顺序不重要:可以以任意顺序设置参数。
- 不可变性:一旦 Computer 对象被创建,就不能被修改。
- 易于扩展:如果需要添加新的属性,只需在 Builder 中添加新的方法,不需要修改 Computer 类。
进一步的优势展示
假设我们现在需要添加一些可选的配置,比如网络适配器和声卡:
public class Computer {
// ... 之前的属性
private String networkAdapter;
private String soundCard;
private Computer(Builder builder) {
// ... 之前的赋值
this.networkAdapter = builder.networkAdapter;
this.soundCard = builder.soundCard;
}
// Getters...
public static class Builder {
// ... 之前的属性
private String networkAdapter;
private String soundCard;
// ... 之前的方法
public Builder networkAdapter(String networkAdapter) {
this.networkAdapter = networkAdapter;
return this;
}
public Builder soundCard(String soundCard) {
this.soundCard = soundCard;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Computer computer1 = new Computer.Builder()
.CPU("Intel i7")
.RAM("16GB")
.storage("512GB SSD")
.GPU("NVIDIA RTX 3070")
.operatingSystem("Windows 10")
.networkAdapter("Intel Wi-Fi 6")
.build();
Computer computer2 = new Computer.Builder()
.CPU("AMD Ryzen 9")
.RAM("32GB")
.storage("1TB NVMe SSD")
.GPU("AMD Radeon RX 6800")
.operatingSystem("Linux")
.soundCard("Creative Sound Blaster")
.build();
}
}
在这个例子中,构建者模式的优势更加明显:
- 处理可选参数:我们可以轻松地添加可选的配置,而不需要创建多个构造函数或使用大量的setter方法。
- 创建不同配置的对象:我们可以轻松地创建具有不同配置的对象,而不需要记住复杂的参数顺序。
- 代码可读性:即使有很多参数,代码仍然保持清晰和易读。
总结
通过这个对比,我们可以看到构建者模式的主要作用:
- 提高可读性:通过方法链的方式设置参数,使得代码更加清晰易读。
- 处理多参数:优雅地处理大量参数,特别是当有些参数是可选的时候。
- 保证不可变性:一旦对象被创建,就不能被修改,这在并发编程中特别有用。
- 分离构建过程:将复杂对象的构建过程与其表示分离,同样的构建过程可以创建不同的表示。
- 控制构建步骤:可以更好地控制构建步骤,例如可以添加一些验证逻辑。
构建者模式特别适用于创建复杂对象,尤其是当对象有多个可选参数或构建步骤时。它可以大大提高代码的可读性、可维护性和灵活性。