概述
建造者(builder)模式,也是我们常见的一种模式,有没有想过我们什么时候适合使用建造者模式呢?
从我们周围世界来说,如果我们想“建造”一辆汽车,我们可以手工一点点地去建造,也可以选择将“建造”汽车分为几个部分,比如建造轮子,建造底盘,建造架子,建造发动机等等,然后再组装在一起,从我们的感知上来说,显然分部分建造更符合我们的认知,因为这样很容易形成标准,给人感觉也更清晰。
同时,在软件中,我们构造一个复杂对象也是一样的道理,我们期待能够一步一步地方便我们的创建。这特别适合那种成员特别多,而且部分是required的,部分是optional的对象的构造。
实现
现在比如有一个用户User类,包含网站登陆用户的信息,我们需要的刻画信息有:
public class User {
private String uid; // required,用户id
private String name; // required,用户名
private String address; // optional,用户地址
private int age; // optional,用户年龄
private String phone; // optional,用户手机号
}
上述User类有两个必须的属性,三个可选属性,如果让你构造一个实例,你会怎么构造呢。大部分,我们会选择用构造函数或者setter和getter属性来处理我们元素的值。那如果我们希望类的元素是final的,即不可变的,用什么方式来处理呢。
显而易见,setter和getter方式是我们最常用的,但是如果希望这个被建造的类初始化后不再修改,或者能够控制参数,就可以考虑下建造者模式了,直接实现示例如下:
public class User {
private final String uid; // required,用户id
private final String name; // required,用户名
private final String address; // optional,用户地址
private final int age; // optional,用户年龄
private final String phone; // optional,用户手机号
// User类只提供getter方法,此处省略
private User(UserBuilder builder) {
this.uid = builder.uid;
this.name = builder.name;
this.address = builder.address;
this.phone = builder.phone;
this.age = builder.age;
}
public static class UserBuilder {
private final String uid;
private final String name;
private String address = "";
private int age = -1;
private String phone = "";
public UserBuilder(String uid, String name) {
this.uid = uid;
this.name = name;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public User build() {
return new User(this);
}
}
public static void main(String[] args) {
User user = new UserBuilder("111", "jack")
.address("china")
.age(20)
.build();
}
}
再举一个例子,比如,有一个接收查询请求的服务,我们构造查询条件,返回响应信息,查询条件是:
public class QueryCondition {
private String query_word; // required,查询词
private String ip; // optional,查询来源地址
private String caller; // optional,查询方
private List<String> ret_fields;// optional,查询返回的数据字段
}
我们该如何设计一个建造者模式来构造该查询条件呢,示例如下:
public class QueryCondition {
private final String query_word; // optional,查询词
private final String ip; // optional,查询来源地址
private final String caller; // optional,查询方
private final List<String> ret_fields;// optional,查询返回的数据字段
public String getQuery_word() {
return query_word;
}
public String getIp() {
return ip;
}
public String getCaller() {
return caller;
}
public List<String> getRet_fields() {
return ret_fields;
}
public QueryCondition(String query_word, String ip, String caller, List<String> ret_fields) {
this.caller = caller;
this.query_word = query_word;
this.ip = ip;
this.ret_fields = ret_fields;
}
}
public class QueryConditionBuilder {
private String query_word = ""; // required,查询词
private String ip = ""; // optional,查询来源地址
private String caller = "default"; // optional,查询方
private List<String> ret_fields = new ArrayList<String>();// optional,查询返回的数据字段
private QueryConditionBuilder() { }
public static QueryConditionBuilder createBuilder() {
return new QueryConditionBuilder();
}
public QueryConditionBuilder setQueryWord(String query_word) throws Exception {
if (query_word == null) {
throw new Exception("query word is null");
}
this.query_word = query_word;
return this;
}
public QueryConditionBuilder setIp(String ip) {
this.ip = ip;
return this;
}
public QueryConditionBuilder setCaller(String caller) {
this.caller = caller;
return this;
}
public QueryConditionBuilder setRetFields(List<String> ret_fields) throws Exception {
if (ret_fields == null || ret_fields.isEmpty()) {
throw new Exception("qeury ret field error");
}
this.ret_fields = ret_fields;
return this;
}
public QueryCondition build() {
return new QueryCondition(query_word, ip, caller, ret_fields);
}
}
我们可以看到,通过建造者模式,我们还可以对构造对象的参数进行统一管理和限制,避免未完整初始化的对象被使用。
以上就是建造者模式,其实也很简单,对不对。