提问:通过对比使用构建者模式和不使用构建者模式,以更好的说明构建者模式的作用
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方法。
- 创建不同配置的对象:我们可以轻松地创建具有不同配置的对象,而不需要记住复杂的参数顺序。
- 代码可读性:即使有很多参数,代码仍然保持清晰和易读。
总结
通过这个对比,我们可以看到构建者模式的主要作用:
- 提高可读性:通过方法链的方式设置参数,使得代码更加清晰易读。
- 处理多参数:优雅地处理大量参数,特别是当有些参数是可选的时候。
- 保证不可变性:一旦对象被创建,就不能被修改,这在并发编程中特别有用。
- 分离构建过程:将复杂对象的构建过程与其表示分离,同样的构建过程可以创建不同的表示。
- 控制构建步骤:可以更好地控制构建步骤,例如可以添加一些验证逻辑。
构建者模式特别适用于创建复杂对象,尤其是当对象有多个可选参数或构建步骤时。它可以大大提高代码的可读性、可维护性和灵活性。