建造者模式是什么?
建造者模式(Builder Pattern)是一种创建型的设计模式,它的主旨是对于构造过程比较复杂的对象,将这一过程从对象分离出来,由另一个对象(建造者)来对其进行构造。
建造者模式最早由 GoF 提出,它的关注点在于抽象,并且对复杂对象的构造处理非常到位,但原本的设计相对比较复杂。Joshua Bloch 在《Effective Java》一书中提出了一种改良版的建造者模式,该设计采用流式的编程风格,使得代码非常简洁易懂。
案例
用一个简单案例来帮助我们理解 Joshua Bloch 的建造者模式:假设现在有一个客户关系管理系统,我们定义了一个类 Customer 来表示客户资料。在创建客户资料时,需要录入客户的姓名、性别、出生年月等信息。
public class Customer {
private String firstName;
private String lastName;
private Gender gender;
private Date dateOfBirth;
private String phoneNumber;
private String email;
private Address address;
public Customer(String firstName, String lastName, Gender gender, Date dateOfBirth, String phoneNumber,
String email, Address address) {
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.dateOfBirth = dateOfBirth;
this.phoneNumber = phoneNumber;
this.email = email;
this.address = address;
}
// getters and setters
}
我们在采集客户资料时,除了客户的姓名是必填的,其他的信息都是选填的。在大部分情况下,我们无法采集到客户的完整信息。如果我们采用全参构造器来创建客户对象,我们仍然不得不为缺失的信息传递值。如果客户资料包含的信息非常之多,达数十项,那么,这将会是一个灾难!
new Customer("Mark", "Huey", Gender.MALE, null, null, "mark-huey@gmail.com", null);
如果我们采用 Joshua Bloch 的设计,那么这个问题将迎刃而解:
public class Customer {
private String firstName;
private String lastName;
private Gender gender;
private Date dateOfBirth;
private String phoneNumber;
private String email;
private Address address;
// getters and setters
public static class Builder {
private String firstName;
private String lastName;
private Gender gender;
private Date dateOfBirth;
private String phoneNumber;
private String email;
private Address address;
public Builder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Builder gender(Gender gender) {
this.gender = gender;
return this;
}
// dateOfBirth method
// phoneNumber method
// email method
// address method
public Customer build() {
return new Customer(this);
}
}
private Customer(Builder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.gender = builder.gender;
this.dateOfBirth = builder.dateOfBirth;
this.phoneNumber = builder.phoneNumber;
this.email = builder.email;
this.address = builder.address;
}
}
现在,我们便可采取一种极为优雅的方式来创建客户资料:
Customer customer = new Customer.Builder("Mark", "Huey")
.gender(Gender.MALE)
.email("mark-huey@gmail.com")
.build();
案例源码
可在 GitHub 上查看上述案例的完整代码。
优点与不足
Joshua Bloch 的建造者模式的设计有如下优点:
- 可以灵活地创建对象,避免繁琐的全参构造方法,或者各种选参构造方法的排列组合。
但也略有不足:
参考资料
以下是本文参考的资料: