创建型设计模式-2.建造者设计模式
一、简介
建造者设计模式(Builder Pattern)是一种创建型设计模式,它专注于逐步构建复杂对象 。它将对象的构建过程与其表示分离,允许相同的构建过程创建不同的表示形式。该模式的目标是简化对象的构建过程,并提供灵活性和可扩展性。
二、核心思想
Builder设计模式的核心思想是将对象的构建过程从其实际表示中解耦。通常情况下,一个对象的构建过程是复杂且多步骤的,使用Builder模式可以将这些步骤分解为独立的方法,从而使得构建过程更加灵活和可控。
三、组成和基本流程
Builder设计模式包含以下几个主要组成部分:
- Director(指导者):负责控制对象的构建过程,按照一定的顺序调用Builder的方法来构建对象。
- Builder(构建者):定义构建对象的接口,包含各个构建步骤的方法。
- ConcreteBuilder(具体构建者):实现Builder接口,负责具体的构建逻辑,并返回构建完成的对象。
- Product(产品):表示最终构建完成的对象,通常具有复杂的内部结构。
Builder设计模式的基本流程如下:
- 定义一个Builder接口,其中包含各个构建步骤的方法。
- 创建具体的Builder类,实现Builder接口,并实现各个构建步骤的具体逻辑。
- 创建一个Director类,它包含一个Builder对象作为成员变量。通过调用Builder的方法,按照特定的顺序构建对象。
- 最终调用Builder的一个方法返回构建完成的对象。
下列是一个简单的建造者设计模式的例子,这段代码演示了如何使用建造者设计模式创建一个电脑对象。
-
首先,我们定义了一个Computer类,它具有一些属性(processor、memory、hardDisk、monitor)以及对应的设置方法。
-
然后,我们定义了一个ComputerBuilder接口,其中包含了构建电脑对象所需的方法(buildProcessor、buildMemory、buildHardDisk、buildMonitor)以及获取构建完成的电脑对象的方法getComputer()。
-
接着,我们实现了一个BasicComputerBuilder类,它是ComputerBuilder接口的具体实现。在BasicComputerBuilder类中,我们实例化了一个Computer对象,并实现了构建电脑各个部件的方法。
-
之后,我们创建了一个ComputerDirector类,它负责指导建造过程。通过调用ComputerBuilder的方法,按照一定的顺序构建电脑对象,并返回构建完成的对象。
-
最后,在Main类中,我们创建了一个BasicComputerBuilder对象作为建造者,创建了一个ComputerDirector对象作为指导者,然后通过指导者来构建电脑对象。最后,我们输出了构建完成的电脑对象的各个属性。
java
class Computer {
private String processor;
private String memory;
private String hardDisk;
private String monitor;
public void setProcessor(String processor) {
this.processor = processor;
}
public void setMemory(String memory) {
this.memory = memory;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
public void setMonitor(String monitor) {
this.monitor = monitor;
}
// 省略其他方法和属性的访问器
}
interface ComputerBuilder {
void buildProcessor();
void buildMemory();
void buildHardDisk();
void buildMonitor();
Computer getComputer();
}
class BasicComputerBuilder implements ComputerBuilder {
private Computer computer;
public BasicComputerBuilder() {
this.computer = new Computer();
}
public void buildProcessor() {
computer.setProcessor("Basic Processor");
}
public void buildMemory() {
computer.setMemory("4GB");
}
public void buildHardDisk() {
computer.setHardDisk("500GB");
}
public void buildMonitor() {
computer.setMonitor("15-inch");
}
public Computer getComputer() {
return computer;
}
}
class ComputerDirector {
public Computer buildComputer(ComputerBuilder builder) {
builder.buildProcessor();
builder.buildMemory();
builder.buildHardDisk();
builder.buildMonitor();
return builder.getComputer();
}
}
public class Main {
public static void main(String[] args) {
ComputerBuilder builder = new BasicComputerBuilder();
ComputerDirector director = new ComputerDirector();
Computer computer = director.buildComputer(builder);
System.out.println("Processor: " + computer.getProcessor());
System.out.println("Memory: " + computer.getMemory());
System.out.println("Hard Disk: " + computer.getHardDisk());
System.out.println("Monitor: " + computer.getMonitor());
}
}
在这个示例中,我们通过建造者模式逐步构建了一个电脑对象。指导者类控制了建造过程,而具体的建造者类负责实际构建对象。最终,我们可以获取到一个完整的电脑对象,并对其进行进一步操作。
四、使用场景
Builder设计模式适用于以下情况:
- 当需要创建具有复杂内部结构的对象时,可以使用Builder模式将构建过程分解为多个简单步骤。
- 当需要构建的对象存在不同的表示形式时,可以使用Builder模式来创建不同的表示。
- 当需要在构建过程中灵活地添加或修改构建步骤时,可以使用Builder模式。
- 实现不可变对象,可以使用Builder模式创建不可变对象。通过将建造者的构建方法设置为私有,并将需要的属性通过构造函数进行初始化,可以确保对象在构建后不可再修改。这样的对象可以提供更好的线程安全性和代码健壮性。
五、具体案例
在这个示例中,我们使用建造者设计模式创建了一个名为 ImmutablePerson
的不可变对象类。
-
在
ImmutablePerson
类中,属性name
、age
和address
被声明为final
,并且没有提供任何修改它们的方法。这样可以确保这些属性在对象创建后不可变。 -
通过私有的构造方法
ImmutablePerson(Builder builder)
,我们将属性的值从Builder
对象传递给了ImmutablePerson
对象,并在构造方法内进行了赋值操作。这样,我们可以在构造对象时保证对象的属性值一致和不可变。 -
Builder
类是一个嵌套类,它提供了链式调用的方法来设置ImmutablePerson
的属性值。每个方法都返回Builder
对象本身,以便可以连续调用多个方法。最后,通过调用build()
方法,我们可以创建并返回一个不可变的ImmutablePerson
对象。
使用该示例,我们可以这样创建一个不可变的 ImmutablePerson
对象:
java
public final class ImmutablePerson {
private final String name;
private final int age;
private final String address;
private ImmutablePerson(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.address = builder.address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
public static class Builder {
private String name;
private int age;
private String address;
public Builder() {
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Builder setAddress(String address) {
this.address = address;
return this;
}
public ImmutablePerson build() {
return new ImmutablePerson(this);
}
}
public static void main(String[] args) {
// Usage example:
ImmutablePerson person = new ImmutablePerson.Builder()
.setName("John")
.setAge(30)
.setAddress("123 Street")
.build();
}
}
在这个示例中,我们通过链式调用 Builder
的方法设置属性的值,并最后调用 build()
方法来创建 ImmutablePerson
对象。一旦对象创建完成,它的属性就是不可变的,无法再修改。
这种方式提供了不可变对象的安全性和线程安全性,因为对象的状态无法在创建后被修改。不可变对象还可以更容易地进行缓存、共享和使用。
lombok例子:
在lombok中,我们使用@Builder
注解会自动生成一个建造者模式的构建者类。下面是一个使用Lombok的@Builder
注解的示例代码:
非常抱歉前面的回答中有些遗漏,确实是多了一些代码。以下是编译前和编译后的代码:
编译前的代码:
java
@Builder
@Getter
@ToString
public class User {
private String name;
private Integer age;
private String bobby;
public static void main(String[] args) {
User.UserBuilder builder = new UserBuilder();
User user = builder.name("jack").age(18).bobby("rap").build();
System.out.println("user = " + user);
}
}
编译后的代码:
java
public class User {
private String name;
private Integer age;
private String bobby;
public static void main(String[] args) {
UserBuilder builder = new UserBuilder();
User user = builder.name("jack").age(18).bobby("rap").build();
System.out.println("user = " + user);
}
User(String name, Integer age, String bobby) {
this.name = name;
this.age = age;
this.bobby = bobby;
}
public static UserBuilder builder() {
return new UserBuilder();
}
public String getName() {
return this.name;
}
public Integer getAge() {
return this.age;
}
public String getBobby() {
return this.bobby;
}
public String toString() {
return "User(name=" + this.getName() + ", age=" + this.getAge() + ", bobby=" + this.getBobby() + ")";
}
public static class UserBuilder {
private String name;
private Integer age;
private String bobby;
UserBuilder() {
}
public UserBuilder name(String name) {
this.name = name;
return this;
}
public UserBuilder age(Integer age) {
this.age = age;
return this;
}
public UserBuilder bobby(String bobby) {
this.bobby = bobby;
return this;
}
public User build() {
return new User(this.name, this.age, this.bobby);
}
public String toString() {
return "User.UserBuilder(name=" + this.name + ", age=" + this.age + ", bobby=" + this.bobby + ")";
}
}
}
请注意,编译后的代码中添加了一些内容,其中包括:
- 在
User
类中,添加了私有构造函数以及对应的属性赋值操作。 - 在
User
类中,添加了getter方法和toString()
方法的具体实现。 - 在
User
类中,添加了静态的builder()
方法,用于创建UserBuilder
对象。 - 在
UserBuilder
类中,添加了构造函数、链式调用方法以及build()
方法的具体实现。
这些额外的代码是Lombok库根据注解自动生成的,它们帮助简化了建造者模式的使用,减少了手动编写重复代码的工作量。这样,您可以更方便地创建和操作User
对象。
六、总结
Builder设计模式的优点包括:
- 可以分步骤构建复杂对象,使构建过程更加灵活和可控。
- 可以创建不同的表示形式,根据复杂的配置项进行定制化构建,提供了更多对象构建的可能性。
- 隔离了构建过程和表示,使得扩展和修改更加方便。
然而,Builder设计模式也存在一些缺点:
- 会增加代码量,因为需要定义和实现多个类。
- 对于简单对象的构建,使用Builder模式可能会显得过于复杂。
总的来说,Builder设计模式在构建复杂对象时非常有用,并提供了灵活性和可扩展性。但在简单情况下,使用该模式可能会带来一定的开销。
七、和工厂设计模式的区别
建造者设计模式和工厂设计模式是两种常见的创建型设计模式,它们都用于创建对象,但在目的和使用方式上存在一些区别。
- 工厂设计模式旨在通过一个工厂类来创建对象,隐藏了具体对象的创建细节,并将客户端与具体对象的实例化过程解耦。客户端只需要通过工厂类来请求所需的对象,而不需要直接实例化对象。工厂模式通常适用于创建不同类型对象的场景,通过使用不同的工厂方法或参数,可以创建不同类型的对象。
- 与之不同,建造者设计模式关注的是逐步构建复杂对象,将对象的构建过程与其表示分离。它允许按照特定的步骤或顺序构建对象,并允许在构建过程中配置对象的各个部分。建造者模式通常适用于创建具有复杂结构或多个可选组件的对象,以及构建过程中涉及多个步骤或变化的对象。
现在,让我们结合生活中的一个例子来说明这两种设计模式的区别。
- 假设你要制作一份披萨。使用工厂模式,你可以有一个披萨工厂,通过向工厂提供披萨的类型(例如,奶酪披萨、素食披萨等),工厂将返回相应类型的披萨对象。这种情况下,你只需要告诉工厂你想要的披萨类型,而不需要知道具体如何制作披萨。
- 现在,假设你要定制一份复杂的披萨,它有多个可选组件,如酱料、配料和尺寸等。这时,建造者模式更适合。你可以有一个披萨建造者,它提供了设置酱料、配料和尺寸等属性的方法。你可以逐步调用这些方法来构建披萨对象,并在构建过程中根据你的喜好进行定制。
总结一下,工厂设计模式适用于创建不同类型的对象,而建造者设计模式适用于逐步构建复杂对象。工厂模式隐藏了对象的创建细节,而建造者模式允许按照特定的步骤或顺序构建对象,并允许在构建过程中进行配置和定制。