建造者模式——java设计模式(五)

简介

建造者模式(Builder Pattern):将一个复杂对象的构建和表示分离,使得同样的构造过程可以创建不同的表示。

  • 对于某些复杂对象,用户无须知道具体的构造细节,只需要指定类型即可。这时可以将对象本身和组装过程分开,并且将内部构成和组装方式隐藏,提供用户调用。
  • 建造者模式关注一步步创建复杂对象,返回一个完整的复杂产品
    抽象工厂模式返回一系列相关产品

结构和实现

  • 角色包括:
    • 抽象建造者:创建对象的接口,包括创建对象各个部件、返回复杂对象。
    • 具体建造者:创建对象的实现类(返回对象可由抽象建造者实现)。
    • 产品:被创建的对象,包含多个组成部分。
    • 指挥者:调用创建者,安排构造对象的次序,完成对象的创建,并与客户端交互。
  • 结构。
    180505.builder.png
  • 客户端调用。
……
Builder  builder = new ConcreteBuilder(); //可通过配置文件实现
Director director = new  Director(builder);
Product product = director.construct();
……

实例

  • 创建游戏角色这一复杂对象,包含类型、性别、脸型、服饰、发型等组成部分。不同类型的角色组成部分的特性有所区别,但是创建步骤大同小异。
  • 游戏角色创建结构图。
    180505.actor.png
  • 客户端调用。
public class Client
{
       public  static void main(String args[])
       {
              ActorBuilder ab; //针对抽象建造者编程
              ab =  (ActorBuilder)XMLUtil.getBean(); //反射生成具体建造者对象

              ActorController ac = new  ActorController();
              Actor actor;
              actor = ac.construct(ab); //通过指挥者创建完整的建造者对象
       }
}

省略指挥者

  • 将指挥者和抽象建造者合并,在抽象建造者中提供construct方法,逐步构建产品。
  • 省略指挥者的游戏角色创建结构图。
    180505.remove.png
  • 客户端调用。
……
              ActorBuilder  ab;
              ab  = (ActorBuilder)XMLUtil.getBean();

              Actor  actor;
              actor = ab.construct();
……

引入钩子方法

  • 使用钩子方法控制某个部件的创建步骤是否进行。可在抽象建造者中提供默认的钩子方法,在具体建造者中可覆盖该方法,以单独控制创建流程。
  • 这样复杂产品的构建顺序可控,构建的组成可控。
  • 引入钩子方法的游戏角色创建图。
    180505.hock.png

优缺点和适用范围

  • 优点:
    • 对象的创建和使用分离。相同的创建过程可以创建不同对象。
    • 符合开闭原则。指挥者类针对抽象建造者编程,可以方便的更换具体建造者,创建不同的对象,增加建造者也不修改源码。
    • 精细控制创建过程。可以分解创建对象的步骤,并且控制整个流程。
  • 缺点:
    • 适用组成相似的产品。组成差异很大的产品不适用。
    • 创建者类较多。特别是产品的内部变化复杂时,会极大提高系统复杂度,增加运行成本。
  • 适用范围:
    • 产品对象内部复杂,包含多个成员变量。
    • 产品对象组成相互依赖,需要一定的顺序。
    • 对象的创建过程独立于该对象的类。可以将创建过程封装在指挥者类中。
    • 需要隔离对象的创建和使用,相同的创建过程创建不同的产品。

jdk中的应用

  • javax.xml.parsers.DocumentBuilder中的parse方法解析输入,创建Document对象。
    • 指挥者为DocumentBuilderImpl,抽象创建者为AbstractDOMParser,创建者为DOMParser,产品为Document。
      180505.DocumentBuilder.png
    public Document parse(InputSource is) throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException(
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                "jaxp-null-input-source", null));
        }
        if (fSchemaValidator != null) {
            if (fSchemaValidationManager != null) {
                fSchemaValidationManager.reset();
                fUnparsedEntityHandler.reset();
            }
            resetSchemaValidator();
        }
        domParser.parse(is);
        Document doc = domParser.getDocument();
        domParser.dropDocumentReferences();
        return doc;
    }

猜你喜欢

转载自blog.csdn.net/qq_40369829/article/details/80208374