创建型模式的一种.
之前说到了工厂模式和原型模式, 他们也是属于创建型的模式.
按照
将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示.
每当我看到这样的描述时都会感觉倒中文在精确描述上的局限性, 而找到信达雅的翻译总是很难. 这句定义需要被充分解释.
实际上, 在之前的prototype里, 我人为它的特点在于clone, 而且clone后的对象可以拥有与被克隆者不同的状态. 这似乎与Builder的后半句定义有些重复, 但在
这里我要提前摆出我的结论: 当你可以使用clone的时候, clone这个方法很多时候不需要你自己去实现. 而Builder则可能需要你对创建实例的过程增加更多可以调整的设置. 关于这一点可以查看本知识库里的其他文章来印证.
Builder, Concrete Builder, Director and Product
我们想要实例化/生产一个Product, 这一步骤可以直接在Client中完成, 但建造者模式为了能够分离构建和表示, 引入了形象的几个角色:
- Builder: 建造者, 通常是抽象的, 需要实际具体的建造者负责实现其方法(注意接口隔离)
- Concrete Builder: 实现Builder中的方法, 通常是存在一批不同的建造者负责以不同的方式建造Product
- Director: 指导建造过程, 实际上是在Builder/Concrete Builder与Client之间塑造了向导, Client只需要让Director知道它需要哪一个Concrete Builder即可, Client不可直接实例化任何Concrete Builder.(除非Director的任务可以直接移交给某个Concrete Builder)
- Product: Client想要获得的产品, 由指定的建造者进行生产.
这些角色之间通常会有如下关系(不绝对):
在Client中, 直接传入ConcreteBuilder构造Director:
// In Client codebase
Director director = new Director(new ConcreteBuilder_2());
Product p = director.ConstructProduct();
实现并不唯一
Java的StringBuilder没有具体的Director, 或者说, StringBuilder类实现的Abstract类即为ConcreteBuilder, 而StringBuilder兼有Director和部分ConcreteBuilder的功能.
此外, 通常产品不设置抽象类, 因为具体生成器生成的产品表示可能相差千里, 不同的表示之间可能不会有太多公共接口. 而Client通过选择Builder已经可以直接指定Product.
建造者模式的实现在不同语言中也有差异, 比如C++中, 往往不设置Builder的虚函数, 而是定义为空方法, 留给实现空间.
有时混合某些角色的功能可能会更符合业务要求.(见
最佳实践
在很多项目中你经常会看到名为 XXXBuilder
的类或抽象类,而这种Builder通常还会以组合的方式将需要构建的对象依赖起来,并且旗帜鲜明地支持连续调用builder method。这样的形式可以用来快速而准确地构建想要的对象,而这样的建造者其实起到了对象配置管理者的作用,它也是一种Director。
比如下面的例子:
// just for demonstration
SomeObject obj = SomeBuilder
.config("next method") // 设置并返回
.header("this") // 设置并返回
.body("xxxx") // 设置并返回
.payload("wrhiqwuhpqff") // 设置并返回
.and() // 有时builder会实现and()方法暂时转移到另一个类型的构建
.code("wqeqqe2f21") // 设置并返回
.otherconfig("2213213ra") // 设置并返回
.build(); // 返回最终对象
在springfamework中,这样的builder随处可见,从http response到security config,这种builder实现无疑增加了代码可读性。
比如在 ResponseEntity
中 的 BodyBuilder
实现类 DefaultBuilder
:
private static class DefaultBuilder implements BodyBuilder {
private final Object statusCode;
private final HttpHeaders headers = new HttpHeaders();
public DefaultBuilder(Object statusCode) {
this.statusCode = statusCode;
}
@Override
public BodyBuilder header(String headerName, String... headerValues) {
for (String headerValue : headerValues) {
this.headers.add(headerName, headerValue);
}
return this;
}
@Override
public BodyBuilder headers(@Nullable HttpHeaders headers) {
if (headers != null) {
this.headers.putAll(headers);
}
return this;
}
@Override
public BodyBuilder headers(Consumer<HttpHeaders> headersConsumer) {
headersConsumer.accept(this.headers);
return this;
}
// some methods are omitted...
@Override
public <T> ResponseEntity<T> build() {
return body(null);
}
@Override
public <T> ResponseEntity<T> body(@Nullable T body) {
return new ResponseEntity<>(body, this.headers, this.statusCode);
}
}
相关模式
除了同属创建型的Prototype已在开篇讨论过, 对于抽象工厂模式来说, Builder模式侧重于一步一步地建造复杂对象(这也是为什么使用ConcreteBuilder), 而抽象工厂侧重于多个系列的产品对象(简单或复杂的).
Builder在最后一步返回对象, AbstractFactory在创建完立即返回.
Composite通常使用Builder模式.