业务背景介绍

在工程模式中讲述的业务背景中,共有三个页面,这三个页面之间是有一定的顺序关系的,永远是第一个页面在前,然后是第二个页面,然后是第三个页面。根据这三个页面的不同,然后构建不同的使用常见的对象。

不使用模式

code

  1. public class JPanelProduct {
  2. private FirstPage firstPage;
  3. private SecondPage secondPage;
  4. private ThirdPage thirdPage;
  5. public void setFirstPage(FirstPage firstPage) {
  6. this.firstPage = firstPage;
  7. }
  8. public void setSecondPage(SecondPage secondPage) {
  9. this.secondPage = secondPage;
  10. }
  11. public void setThirdPage(ThirdPage thirdPage) {
  12. this.thirdPage = thirdPage;
  13. }
  14. }
  15. public class Client {
  16. public static void main(String[] args) {
  17. JPanelProduct c7xProduct = new JPanelProduct();
  18. c7xProduct.setFirstPage(new C7xFirstPage());
  19. c7xProduct.setSecondPage(new C7xSecondPage());
  20. c7xProduct.setThirdPage(new C7xThirdPage());
  21. JPanelProduct mdcProduct = new JPanelProduct();
  22. mdcProduct.setFirstPage(new C7xFirstPage());
  23. mdcProduct.setSecondPage(new C7xSecondPage());
  24. mdcProduct.setThirdPage(new MdcThirdPage());
  25. }
  26. }

肉眼可见,c7xProduct和mdcProduct这两个product在创建的时候,有重复的文件的创建过程,那么是否有必要将这个重复的过程提炼出一个新的类或者方法进行处理呢?
个人建议是,见仁见智,如果只有一种类型的产品,那么其实并不需要;如果是有多种产品需要创建,则建议使用建造者模式。

uml

设计模式—生成器builder - 图1

使用模式

code

  1. public interface Builder {
  2. void buildFirstPage();
  3. void buildSecondPage();
  4. void buildThirdPage();
  5. }
  6. public class C7xBuilder implements Builder {
  7. private JPanelProduct product;
  8. private final C7xFactory c7xFactory;
  9. public C7xBuilder() {
  10. this.c7xFactory = new C7xFactory();;
  11. }
  12. @Override
  13. public void buildFirstPage() {
  14. product.setFirstPage(c7xFactory.createFirstPage());
  15. }
  16. @Override
  17. public void buildSecondPage() {
  18. product.setSecondPage(c7xFactory.createSecondPage());
  19. }
  20. @Override
  21. public void buildThirdPage() {
  22. product.setThirdPage(c7xFactory.createThirdPage());
  23. }
  24. public JPanelProduct getProduct() {
  25. return product;
  26. }
  27. }
  28. public class Director {
  29. private final Builder builder;
  30. public Director(Builder builder) {
  31. this.builder = builder;
  32. }
  33. public void construct() {
  34. builder.buildFirstPage();
  35. builder.buildSecondPage();
  36. builder.buildThirdPage();
  37. }
  38. }
  39. public class Client {
  40. public static void main(String[] args) {
  41. C7xBuilder c7xBuilder = new C7xBuilder();
  42. Director director = new Director(c7xBuilder);
  43. director.construct();
  44. JPanelProduct product = c7xBuilder.getProduct();
  45. }
  46. }

uml

设计模式—生成器builder - 图2 Builder模式分为产品构建部分和商品装配部分:

  1. Director负责的是整个的构建过程,是相对不会变化的部分;在产品的复杂度较高的时候,比较适合用这种模式;
  2. Builder则负责的是产品的各个部件的具体构成,是会随着不同的产品而变化的部分;这里有个问题,为什么不将getProduct方法放在Builder里面,而是有具体的Builder来实现?是因为产品构造流程是固定的,但是每个builder生成的产品是可以不一样的,所以这里将product放在具体的builer类里面来处理。如果所有的产品都是相同的,则可以放到builder里面。

本质

生成器模式的重心在于分离构建算法和具体的构造实现,从而使得构建算法可以重用,具体的构造实现可以很方便的扩展和切换

扩展

从代码或UML图中可以看到,Director负责的部分是产品的构建过程,类的职责相对单一。有一种常见的方式是将Director融入到Client中,直接由Client负责产品的构建。因为在实际的产品构建过程中,可能会随着Client的状态、需求,而有比较大的变化。建议:

  1. 如果构建过程稳定,则Director可以独立出来;
  2. 如果建构过程不稳定,则考虑将Client和Director进行融合,降到Client中;为什么将构建过程放到Client端,而不是Builder?builder里面一般是具体产品的部件的构建,这些构建参数会由于Client的不同而所变化,因此需要放在Client中,根据Client的内容的变化,来针对性的构建builder的不同part部分。
  1. public class MdcBuilder {
  2. private JPanelProduct product;
  3. public MdcBuilder setFirstPage() {
  4. product.setFirstPage(new C7xFirstPage());
  5. return this;
  6. }
  7. public MdcBuilder setSecondPage() {
  8. product.setSecondPage(new C7xSecondPage());
  9. return this;
  10. }
  11. public MdcBuilder setThirdPage() {
  12. product.setThirdPage(new C7xThirdPage());
  13. return this;
  14. }
  15. public JPanelProduct builder() {
  16. return product;
  17. }
  18. }
  19. public class Client {
  20. public static void main(String[] args) {
  21. MdcBuilder mdcBuilder = new MdcBuilder().setFirstPage().setSecondPage().setThirdPage();
  22. JPanelProduct builder = mdcBuilder.builder();
  23. }
  24. }

对应的UML变化为: 设计模式—生成器builder - 图3

  1. 在实际的生产过程中,builder类中的方法一般会带有参数,由Client端设置进去,而不是当前的这种这么简单;
  2. Builder类返回的是Builder自身,这样在高级语言中,就能更优雅;
  3. 对每个参数的检查,一般会放在到set方法中;对整个builder类的检查则会放到builder方法中;

    与其他模式的对比

与抽象工程的比较

在原始状态下,抽象工程模式与builder模式是很相似的。可以认为抽象工程模式 + Director就等于builder模式。但是他们又有不同,其中抽象工厂的目的是为了返回一簇产品,builder则是为了返回一个完成的产品。从UML图中看

设计模式—生成器builder - 图4 设计模式—生成器builder - 图5

与模板模式比较

相同点

  1. 都是将不变化的地方提炼出来,变化的地方由不同的子类或者其他类代理完成;

不同点

  1. 目的不同,模板模式是为了行为型设计模式,主要是为了实现算法;
  2. 模板模式变化的点由其子类实现;生成器模式则是由代理builder类实现;