目的

Separates object construction from its representation, always creates the same type of object. 刻意将一个复杂的对象的「构建」和「表示」分离,使得同样的构建过程能够创造不同的表示。

动机

分离复杂的对象构造过程,转而以 Builder 对象做替代。

适用性

对象或组件涉及高复杂性时,需要根据在不同环境生成不同对象的实例时,处理很多共享相同属性的小型对象或组件时(Flyweight),在编写只需要满足一个API契约的其它对象的实例对象时。

  • 创建复杂对象的算法需要独立于该对象的组成部分以及它们的装配方式的时候。
  • 当构造的过程必须允许被构造的对象有不同的表示的时候。

代码结构和实现

  1. class NodeListBuilder {
  2. static splitTokens(text: string): string[];
  3. static getTokenType(token: string): string;
  4. private builderMap = {
  5. Element: new ElementBuilder(),
  6. Fragment: new FragmentBuilder(),
  7. };
  8. constructor(tokens: string) {
  9. this.nodeList = NodeListBuilder.splitTokens(tokens)
  10. .map(token => this.parse(token));
  11. }
  12. parse(token: string) {
  13. const type = NodeBuilder.getTokenType(token);
  14. const builder = builderMap[type];
  15. return builder ? builder.parse(token) : new TextElement(token);
  16. }
  17. getNodeList() {
  18. return this.nodeList;
  19. }
  20. }
  21. class ElementBuilder {
  22. parse(token: string): Element;
  23. }
  24. class FragmentBuilder {
  25. parse(token: string): Fragment;
  26. }
  27. class HTMLFragment {
  28. static getTokens(text: string);
  29. constructor(text: string) {
  30. const nodeList = new NodeListBuilder(text).getNodeList();
  31. // ... do something
  32. }
  33. }
  • 不用多解释,$(),就是一个接近完美的 Builder!
  • UI 编排之中,用于创造 Node 对象的过程也可以作为 Builder,因为 Builder 是递归构造生成树的;

实现反思

  • 装配和构造接口,应该考虑到通用性和广泛性,以满足各类具体的构造器。

效果

  • 它可以使你改变一个产品的内部表示。自然也隐藏了这个产品的表示和内部结构,以及装配过程。
  • 它将构造代码和表示代码分开。构建逻辑和表示层逻辑「解耦合」。客户并不需要理解定义产品内部结构的类的所有信息。
  • 可以在构造过程中做更为精细的控制。

关联

  • Composite 模式往往是 Builder 生成的。
  • Abstract Factory 关注产品族的构建,而 Builder 则关注构建过程。