假设有一个Java实体类定义:
public class Request {
private String type;
private String op;
private PageInfo pageInfo;
public static class PageInfo {
private Integer pageNum;
private Integer pageSize;
}
// 省略getter和setter...
}
在代码中创建这个对象,需要写以下代码:
public static void main(String[] args) {
// 创建PageInfo
Request.PageInfo pageInfo = new Request.PageInfo();
pageInfo.setPageNum(1);
pageInfo.setPageSize(10);
// 创建Request
Request request = new Request();
request.setOp("op");
request.setType("type");
request.setPageInfo(pageInfo);
// 使用request...
}
由于对象创建与对象初始化相互分离,以上代码看起来十分冗长,每个属性都需要一条setter语句来赋值,当属性数量较多时看起来非常不优雅。另外,由于嵌套类的存在,创建最外层对象之前,必须把所有内层对象先创建完毕,实在是恶心至极。
针对以上问题,熟悉设计模式的朋友应该很快就能想到使用Builder模式改写这个类:
public class Request {
private String type;
private String op;
private PageInfo pageInfo;
private Request(String type, String op, PageInfo pageInfo) {
this.type = type;
this.op = op;
this.pageInfo = pageInfo;
}
// 省略getter和setter...
public static RequestBuilder builder() {
return new RequestBuilder();
}
public static class PageInfo {
private Integer pageNum;
private Integer pageSize;
private PageInfo(Integer pageNum, Integer pageSize) {
this.pageNum = pageNum;
this.pageSize = pageSize;
}
// 省略getter和setter...
public static PageInfoBuilder builder() {
return new PageInfoBuilder();
}
public static class PageInfoBuilder {
private Integer pageNum;
private Integer pageSize;
public PageInfoBuilder pageNum(Integer pageNum) {
this.pageNum = pageNum;
return this;
}
public PageInfoBuilder pageSize(Integer pageSize) {
this.pageSize = pageSize;
return this;
}
public PageInfo build() {
return new PageInfo(this.pageNum, this.pageSize);
}
}
}
public static class RequestBuilder {
private String type;
private String op;
private PageInfo pageInfo;
public RequestBuilder type(String type) {
this.type = type;
return this;
}
public RequestBuilder op(String op) {
this.op = op;
return this;
}
public RequestBuilder pageInfo(PageInfo pageInfo) {
this.pageInfo = pageInfo;
return this;
}
public Request build() {
return new Request(this.type, this.op, this.pageInfo);
}
}
}
这样就能使用流畅的链式调用创建对象,看起来行云流水:
public static void main(String[] args) {
Request request = Request.builder()
.op("op")
.type("type")
.pageInfo(Request.PageInfo.builder()
.pageNum(1)
.pageSize(10)
.build())
.build();
// 使用request...
}
但是问题来了,假设Request
这个对象是一个第三方框架或类库中的类,且并没有按照Builder模式来实现,由于无法修改该类的代码,我们也只能被迫使用setter方法来创建这个对象。在这种情况下,我们还能拥有像之前一样丝滑般的体验吗?
下面介绍一个简单的小技巧解决这个问题。
通用Builder工具类
public class BuilderUtils {
public static <T> T build(T obj, Consumer<T> applyFunc) {
applyFunc.accept(obj);
return obj;
}
}
上面的工具类有一个build
方法,这个方法只是在一个指定的对象obj
上调用了我们传入的一个任意操作函数applyFunc
。有了这个方法,就能在任意对象上实现类似Builder模式的写法。
import static byx.test.BuilderUtils.build;
public static void main(String[] args) {
Request request = build(new Request(), r -> {
r.setOp("op");
r.setType("type");
r.setPageInfo(build(new Request.PageInfo(), p -> {
p.setPageNum(1);
p.setPageSize(10);
}));
});
// 使用request...
}
这个方法巧妙地将对象创建与对象初始化结合在了一起。实际上这种方法比Builder模式更灵活,因为build
方法传入的lambda表达式中可以执行任意操作,而不仅仅是给对象属性赋值。我们可以在其中加入任意复杂的逻辑,比如根据某些条件为对象属性赋予不同的值,或者执行初始化逻辑等。更重要的是,所有操作都包含在一个语句中,而不会打散在数不清的setter调用中。