创建型模式的一种.
之前说到了工厂模式和原型模式, 他们也是属于创建型的模式.
按照这本书对Builder模式的意图的简单定义, 它是:

将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示.

每当我看到这样的描述时都会感觉倒中文在精确描述上的局限性, 而找到信达雅的翻译总是很难. 这句定义需要被充分解释.
实际上, 在之前的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想要获得的产品, 由指定的建造者进行生产.

这些角色之间通常会有如下关系(不绝对): 建造者模式 - 图1在Client中, 直接传入ConcreteBuilder构造Director:

  1. // In Client codebase
  2. Director director = new Director(new ConcreteBuilder_2());
  3. Product p = director.ConstructProduct();

实现并不唯一

Java的StringBuilder没有具体的Director, 或者说, StringBuilder类实现的Abstract类即为ConcreteBuilder, 而StringBuilder兼有Director和部分ConcreteBuilder的功能.

此外, 通常产品不设置抽象类, 因为具体生成器生成的产品表示可能相差千里, 不同的表示之间可能不会有太多公共接口. 而Client通过选择Builder已经可以直接指定Product.

建造者模式的实现在不同语言中也有差异, 比如C++中, 往往不设置Builder的虚函数, 而是定义为空方法, 留给实现空间.

有时混合某些角色的功能可能会更符合业务要求.(中译版P70).

最佳实践

在很多项目中你经常会看到名为 XXXBuilder 的类或抽象类,而这种Builder通常还会以组合的方式将需要构建的对象依赖起来,并且旗帜鲜明地支持连续调用builder method。这样的形式可以用来快速而准确地构建想要的对象,而这样的建造者其实起到了对象配置管理者的作用,它也是一种Director。

比如下面的例子:

  1. // just for demonstration
  2. SomeObject obj = SomeBuilder
  3. .config("next method") // 设置并返回
  4. .header("this") // 设置并返回
  5. .body("xxxx") // 设置并返回
  6. .payload("wrhiqwuhpqff") // 设置并返回
  7. .and() // 有时builder会实现and()方法暂时转移到另一个类型的构建
  8. .code("wqeqqe2f21") // 设置并返回
  9. .otherconfig("2213213ra") // 设置并返回
  10. .build(); // 返回最终对象

在springfamework中,这样的builder随处可见,从http response到security config,这种builder实现无疑增加了代码可读性。
比如在 ResponseEntity 中 的 BodyBuilder 实现类 DefaultBuilder :

  1. private static class DefaultBuilder implements BodyBuilder {
  2. private final Object statusCode;
  3. private final HttpHeaders headers = new HttpHeaders();
  4. public DefaultBuilder(Object statusCode) {
  5. this.statusCode = statusCode;
  6. }
  7. @Override
  8. public BodyBuilder header(String headerName, String... headerValues) {
  9. for (String headerValue : headerValues) {
  10. this.headers.add(headerName, headerValue);
  11. }
  12. return this;
  13. }
  14. @Override
  15. public BodyBuilder headers(@Nullable HttpHeaders headers) {
  16. if (headers != null) {
  17. this.headers.putAll(headers);
  18. }
  19. return this;
  20. }
  21. @Override
  22. public BodyBuilder headers(Consumer<HttpHeaders> headersConsumer) {
  23. headersConsumer.accept(this.headers);
  24. return this;
  25. }
  26. // some methods are omitted...
  27. @Override
  28. public <T> ResponseEntity<T> build() {
  29. return body(null);
  30. }
  31. @Override
  32. public <T> ResponseEntity<T> body(@Nullable T body) {
  33. return new ResponseEntity<>(body, this.headers, this.statusCode);
  34. }
  35. }

相关模式

除了同属创建型的Prototype已在开篇讨论过, 对于抽象工厂模式来说, Builder模式侧重于一步一步地建造复杂对象(这也是为什么使用ConcreteBuilder), 而抽象工厂侧重于多个系列的产品对象(简单或复杂的).
Builder在最后一步返回对象, AbstractFactory在创建完立即返回.
Composite通常使用Builder模式.