zoukankan      html  css  js  c++  java
  • 八.建造者模式

    在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。例如,计算机是由 OPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。

    生活中这样的例子很多,如游戏中的不同角色,其性别、个性、能力、脸型、体型、服装、发型等特性都有所差异;还有汽车中的方向盘、发动机、车架、轮胎等部件也多种多样;每封电子邮件的发件人、收件人、主题、内容、附件等内容也各不相同。

    以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。

    模式的定义与特点

    建造者(Builder)模式的定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

    该模式的主要优点如下:

    1. 各个具体的建造者相互独立,有利于系统的扩展。
    2. 客户端不必知道产品内部组成的细节,便于控制细节风险。


    其缺点如下:

    1. 产品的组成部分必须相同,这限制了其使用范围。
    2. 如果产品的内部变化复杂,该模式会增加很多的建造者类。


    建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

    模式的结构与实现

    建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成,现在我们来分析其基本结构和实现方法。

    1. 模式的结构

    建造者(Builder)模式的主要角色如下。

    1. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个滅部件。
    2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
    3. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
    4. 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。


    其结构图如图 1 所示。

    建造者模式的结构图
    图1 建造者模式的结构图

    2. 模式的实现

    图 1 给出了建造者(Builder)模式的主要结构,其相关类的代码如下。

    (1) 产品角色:包含多个组成部件的复杂对象。

    1. class Product
    2. {
    3. private String partA;
    4. private String partB;
    5. private String partC;
    6. public void setPartA(String partA)
    7. {
    8. this.partA=partA;
    9. }
    10. public void setPartB(String partB)
    11. {
    12. this.partB=partB;
    13. }
    14. public void setPartC(String partC)
    15. {
    16. this.partC=partC;
    17. }
    18. public void show()
    19. {
    20. //显示产品的特性
    21. }
    22. }


    (2) 抽象建造者:包含创建产品各个子部件的抽象方法。

    1. abstract class Builder
    2. {
    3. //创建产品对象
    4. protected Product product=new Product();
    5. public abstract void buildPartA();
    6. public abstract void buildPartB();
    7. public abstract void buildPartC();
    8. //返回产品对象
    9. public Product getResult()
    10. {
    11. return product;
    12. }
    13. }


    (3) 具体建造者:实现了抽象建造者接口。

    1. public class ConcreteBuilder extends Builder
    2. {
    3. public void buildPartA()
    4. {
    5. product.setPartA("建造 PartA");
    6. }
    7. public void buildPartB()
    8. {
    9. product.setPartA("建造 PartB");
    10. }
    11. public void buildPartC()
    12. {
    13. product.setPartA("建造 PartC");
    14. }
    15. }


    (4) 指挥者:调用建造者中的方法完成复杂对象的创建。

    1. class Director
    2. {
    3. private Builder builder;
    4. public Director(Builder builder)
    5. {
    6. this.builder=builder;
    7. }
    8. //产品构建与组装方法
    9. public Product construct()
    10. {
    11. builder.buildPartA();
    12. builder.buildPartB();
    13. builder.buildPartC();
    14. return builder.getResult();
    15. }
    16. }


    (5) 客户类。

    1. public class Client
    2. {
    3. public static void main(String[] args)
    4. {
    5. Builder builder=new ConcreteBuilder();
    6. Director director=new Director(builder);
    7. Product product=director.construct();
    8. product.show();
    9. }
    10. }

    模式的应用实例

    【例1】用建造者(Builder)模式描述客厅装修。

    分析:客厅装修是一个复杂的过程,它包含墙体的装修、电视机的选择、沙发的购买与布局等。客户把装修要求告诉项目经理,项目经理指挥装修工人一步步装修,最后完成整个客厅的装修与布局,所以本实例用建造者模式实现比较适合。

    这里客厅是产品,包括墙、电视和沙发等组成部分。具体装修工人是具体建造者,他们负责装修与墙、电视和沙发的布局。项目经理是指挥者,他负责指挥装修工人进行装修。

    另外,客厅类中提供了 show() 方法,可以将装修效果图显示出来(点此下载装修效果图的图片)。客户端程序通过对象生成器类 ReadXML 读取 XML 配置文件中的装修方案数据(点此下载 XML 文件),调用项目经理进行装修。其类图如图 2 所示。

    客厅装修的结构图
    图2 客厅装修的结构图


    程序代码如下:

    1. package Builder;
    2. import java.awt.*;
    3. import javax.swing.*;
    4. public class ParlourDecorator
    5. {
    6. public static void main(String[] args)
    7. {
    8. try
    9. {
    10. Decorator d;
    11. d=(Decorator) ReadXML.getObject();
    12. ProjectManager m=new ProjectManager(d);
    13. Parlour p=m.decorate();
    14. p.show();
    15. }
    16. catch(Exception e)
    17. {
    18. System.out.println(e.getMessage());
    19. }
    20. }
    21. }
    22. //产品:客厅
    23. class Parlour
    24. {
    25. private String wall; //墙
    26. private String TV; //电视
    27. private String sofa; //沙发
    28. public void setWall(String wall)
    29. {
    30. this.wall=wall;
    31. }
    32. public void setTV(String TV)
    33. {
    34. this.TV=TV;
    35. }
    36. public void setSofa(String sofa)
    37. {
    38. this.sofa=sofa;
    39. }
    40. public void show()
    41. {
    42. JFrame jf=new JFrame("建造者模式测试");
    43. Container contentPane=jf.getContentPane();
    44. JPanel p=new JPanel();
    45. JScrollPane sp=new JScrollPane(p);
    46. String parlour=wall+TV+sofa;
    47. JLabel l=new JLabel(new ImageIcon("src/"+parlour+".jpg"));
    48. p.setLayout(new GridLayout(1,1));
    49. p.setBorder(BorderFactory.createTitledBorder("客厅"));
    50. p.add(l);
    51. contentPane.add(sp,BorderLayout.CENTER);
    52. jf.pack();
    53. jf.setVisible(true);
    54. jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    55. }
    56. }
    57. //抽象建造者:装修工人
    58. abstract class Decorator
    59. {
    60. //创建产品对象
    61. protected Parlour product=new Parlour();
    62. public abstract void buildWall();
    63. public abstract void buildTV();
    64. public abstract void buildSofa();
    65. //返回产品对象
    66. public Parlour getResult()
    67. {
    68. return product;
    69. }
    70. }
    71. //具体建造者:具体装修工人1
    72. class ConcreteDecorator1 extends Decorator
    73. {
    74. public void buildWall()
    75. {
    76. product.setWall("w1");
    77. }
    78. public void buildTV()
    79. {
    80. product.setTV("TV1");
    81. }
    82. public void buildSofa()
    83. {
    84. product.setSofa("sf1");
    85. }
    86. }
    87. //具体建造者:具体装修工人2
    88. class ConcreteDecorator2 extends Decorator
    89. {
    90. public void buildWall()
    91. {
    92. product.setWall("w2");
    93. }
    94. public void buildTV()
    95. {
    96. product.setTV("TV2");
    97. }
    98. public void buildSofa()
    99. {
    100. product.setSofa("sf2");
    101. }
    102. }
    103. //指挥者:项目经理
    104. class ProjectManager
    105. {
    106. private Decorator builder;
    107. public ProjectManager(Decorator builder)
    108. {
    109. this.builder=builder;
    110. }
    111. //产品构建与组装方法
    112. public Parlour decorate()
    113. {
    114. builder.buildWall();
    115. builder.buildTV();
    116. builder.buildSofa();
    117. return builder.getResult();
    118. }
    119. }
    1. package Builder;
    2. import javax.xml.parsers.*;
    3. import org.w3c.dom.*;
    4. import java.io.*;
    5. class ReadXML
    6. {
    7. public static Object getObject()
    8. {
    9. try
    10. {
    11. DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
    12. DocumentBuilder builder=dFactory.newDocumentBuilder();
    13. Document doc;
    14. doc=builder.parse(new File("src/Builder/config.xml"));
    15. NodeList nl=doc.getElementsByTagName("className");
    16. Node classNode=nl.item(0).getFirstChild();
    17. String cName="Builder."+classNode.getNodeValue();
    18. System.out.println("新类名:"+cName);
    19. Class<?> c=Class.forName(cName);
    20. Object obj=c.newInstance();
    21. return obj;
    22. }
    23. catch(Exception e)
    24. {
    25. e.printStackTrace();
    26. return null;
    27. }
    28. }
    29. }


    程序运行结果如图 3 所示。

    客厅装修的运行结果
    图3 客厅装修的运行结果

    模式的应用场景

    建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。

    • 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
    • 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。

    模式的扩展

    建造者(Builder)模式在应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。

  • 相关阅读:
    欧拉函数
    新博客地址
    socket编程
    文件操作
    python安装扩展”unable to find vcvarsall.bat“的解决办法
    PYTHON以及插件安装
    梯式结构
    PHPSTORM配置
    CSRF攻击
    js的一些奇葩用法
  • 原文地址:https://www.cnblogs.com/chenhg/p/13491846.html
Copyright © 2011-2022 走看看