定义

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

结构和说明

创建型模式-生成器模式 - 图1

示例代码

  1. public class BuilderDemo {
  2. /**
  3. * 被构建的产品对象的接口
  4. */
  5. public static interface Product {
  6. // 定义产品的操作
  7. }
  8. /**
  9. * 生成器接口,定义创建一个产品对象所需要的各个部件的操作
  10. */
  11. public static interface Builder {
  12. /**
  13. * 示意方法,构建某个部件
  14. */
  15. void buildPart();
  16. }
  17. /**
  18. * 具体的生成器实现对象
  19. */
  20. public static class ConcreteBuilder implements Builder {
  21. /**
  22. * 生成器最终构建的产品对象
  23. */
  24. private Product resultProduct;
  25. /**
  26. * 获取 生成器最终构建的产品对象
  27. *
  28. * @return 生成器最终构建的产品对象
  29. */
  30. public Product getResult() {
  31. return resultProduct;
  32. }
  33. @Override
  34. public void buildPart() {
  35. // 构建某个部件的功能处理
  36. }
  37. }
  38. /**
  39. * 指导者,指导使用生成器的接口来构建产品的对象
  40. */
  41. public static class Director {
  42. /**
  43. * 持有当前需要使用的生成器对象
  44. */
  45. private Builder builder;
  46. /**
  47. * 构造方法,传入生成器对象
  48. *
  49. * @param builder 生成器对象
  50. */
  51. public Director(Builder builder) {
  52. this.builder = builder;
  53. }
  54. /**
  55. * 示意方法,指导生成器构建最终的产品对象
  56. */
  57. public void construct() {
  58. // 通过使用生成器接口来构建最终的产品对象
  59. builder.buildPart();
  60. }
  61. }
  62. public static class Client {
  63. public static void main(String[] args) {
  64. // 选择生成器,创建指导者
  65. ConcreteBuilder builder = new ConcreteBuilder();
  66. Director director = new Director(builder);
  67. // 指导生成器构建最终的产品对象
  68. director.construct();
  69. // 获取 生成器最终构建的产品对象
  70. Product product = builder.getResult();
  71. }
  72. }
  73. }

调用顺序

创建型模式-生成器模式 - 图2

构建复杂对象

示例代码

  1. public class BuildObjDemo {
  2. @Getter
  3. @ToString
  4. public static class Demo {
  5. private String phoneNumber;
  6. private String name;
  7. private Integer age;
  8. /**
  9. * 构造方法私有化,只允许内部类 Builder 调用
  10. *
  11. * @param builder
  12. */
  13. private Demo(Builder builder) {
  14. this.phoneNumber = builder.getPhoneNumber();
  15. this.name = builder.getName();
  16. this.age = builder.getAge();
  17. }
  18. /**
  19. * 其他的操作
  20. */
  21. public void someOperation() {
  22. //
  23. }
  24. /**
  25. * Demo 对象构建器
  26. */
  27. @Getter
  28. public static class Builder {
  29. // ################### 拥有和 Demo 一样的属性信息 ##########
  30. private String phoneNumber;
  31. private String name;
  32. private Integer age;
  33. // ################### 必选参数设置 #######################
  34. public Builder(String phoneNumber) {
  35. this.phoneNumber = phoneNumber;
  36. }
  37. // ################### 可选参数设置 #######################
  38. public Builder setPhoneNumber(String phoneNumber) {
  39. this.phoneNumber = phoneNumber;
  40. return this;
  41. }
  42. public Builder setName(String name) {
  43. this.name = name;
  44. return this;
  45. }
  46. public Builder setAge(Integer age) {
  47. this.age = age;
  48. return this;
  49. }
  50. // ################### 真正的构建对象并返回 ################
  51. public Demo build() {
  52. return new Demo(this);
  53. }
  54. }
  55. }
  56. public static class Client {
  57. public static void main(String[] args) {
  58. Demo demo = new Demo.Builder("155****2277").setName("*学成").build();
  59. System.out.println(demo);
  60. }
  61. }
  62. }

约束规则

通常有两个地方可以添加约束规则。

  • 一个是构建器的每一个类似于 setter 的方法,可以在这里进行单个数据的约束规则校验,如果不正确,就抛出 IllegalStateException。
  • 另一个是构建器的 build 方法,在构建目标对象之前,对所有数据都可以进行数据的规则校验,尤其是那些涉及到几个数据之间的约束关系,在这里校验会比较合适。如果不正确,就抛出 IllegalStateException。

优缺点

优点

  • 松散耦合

生成器模式可以用一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。生成器模式正是把产品构建过程独立出来,使它和具体产品的表现松散耦合,从而使得构建算法可以复用,而具体产品表现行为也可以灵活地、方便地扩展和切换。

  • 可以很容易地改变产品的内部表示

在生成器模式中,由于 Builder 对象只是提供接口给 Director 使用,那么具体的部件创建和装配方式是被 Builder 接口隐藏了的, Director 并不知道这些具体的实现细节。这样一来,要想改变产品的内部表示,只需要切换 Builder 的具体实现即可。不用管 Director, 因此变得很容易。

  • 更好的复用性

生成器模式很好的实现了构建算法和具体产品实现的分离。这样一来,使得构建产品的算法可以复用。同样的道理,具体产品的实现也可以复用,同一个产品的实现,可以配合不同的构建算法使用。

思考

本质

分离整体构建算法和部件构建。

何时选用

  • 如果构建对象的算法,应该独立于该对象的组成部分以及它们的装配方式时。
  • 如果同一构建过程有着不同表示时。

相关模式

  • 生成器模式和工厂方法模式

这两个模式可以组合使用。
生成器模式的 Builder 实现中,通常需要选择具体的部件实现。一个可行的方案就是实现为工厂方法,通过工厂方法来获取具体的部件对象,然后再进行部件的装配。

  • 生成器模式和抽象工厂模式

这两个模式既相似又有区别,也可以组合使用。
区别: 抽象工厂模式的主要目的是创建产品簇,这个产品簇里面的单个单品就相当于是构成一个复杂对象的部件对象,抽象工厂对象创建完成后就立即返回整个产品簇,而生成器模式的主要目的是按照构造算法,一步一步来构建一个复杂的产品对象,通常要等到整个构建过程结束后,才会得到最终的产品对象。
事实上,这两个模式可以组合使用的。在生成器模式的 Builder 实现中,需要创建各个部件对象,而这些部件对象是有关联的,通常是构成一个复杂对象的部件对象。也就是说,Builder 实现中,需要获取构成一个复杂对象的产品簇,那自然就可以使用抽象工厂模式来实现。这样一来,由抽象工厂模式负责了部分对象的创建,Builder 实现里面则主要负责产品对象整体的构建了。

  • 生成器模式和模版方法模式

这也是两个非常相似的模式。初看之下,不回觉得这两个模式会有什么关联。但是仔细一思考,却发现两个模式在功能上很类似。模版方法主要是用来定义算法的骨架,把算法中的某些步骤延迟到子类中实现。再想想生成器模式,Director 用来定义整体的构建算法,把算法中的某些涉及到具体部件对象的创建和装配的功能,委托给具体的 Builder 来实现。
虽然生成器不是延迟到子类,是委托给 Builder,但那只是具体实现方式上的差别,从始至终上看两个模式很类似,都是定义一个固定的算法骨架,然后把算法中的具体步骤交给其他类来完成,都能实现整体算法步骤和某些具体步骤实现的分离。
当然这两个模式也有很大的区别,首先是模式的目的,生成器模式是用来构建复杂对象的,而模版方法是用来定义算法骨架,尤其是一些复杂业务的处理算法的骨架;其次是模式的实现,生成器模式是采用委托的方法,而模版方法采用的是继承的方式;另外从使用的复杂度上,生成器模式需要组合 Director 和 Builder 对象,然后才能开始构建,要等构建完成后才能获取最终对象,而模版方法就没有这么麻烦,直接使用子类对象即可。

  • 生成模式和组合模式

对于复杂的组合结构,可以生成器模式一步一步构建。