• JAVA设计模式之建造者模式 IT


    一、定义

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

      

           建造者模式结构图,如下图1-1所示:

    图 1-1 

    二、实例展示

       Product类:产品类,由多个部件组成。

    1 public class Product{
    2 List<String> parts = new ArrayList<String>(); 3 public void Add(String part){ 4 parts.Add(part); 5 }
    6 public void Show(){
    7 System.out.println("产品创建----");
    8 for(String part : parts){
    9 System.out.println(part);
    10 }
    11 } 12}

       Builder类:抽象建造者类,确定产品由两个部件PartA和PartB组成,并声明一个得到产品建造后结果的方法GetResult。

    1  public abstract class Builder{
    2     public abstract void BuildPartA();
    3 public abstract void BuildPartB();
    4 public abstract Product GetResult(); 5 }

       ConcreteBuilder1:具体建造者类。

    1 public class ConcreteBuilder1 extends Builder{
    2 private Product product = new Product();

    3 @override 4 public void BuildPartA(){ 5 product.Add("部件A"); 6 }

    7 @Override
    8 public void BuildPartB(){
    9 product.Add("部件B");
    10 }

    11 @override
    12 public void Product GetResult(){
    13 result product;
    14 } 15}

              ConcreteBuilder2:具体建造者类。

    1 public class ConcreteBuilder2 extends Builder{
    2 private Product product = new Product();

    3 @override 4 public void BuildPartA(){ 5 product.Add("部件X"); 6 }

    7 @override
    8 public void BuildPartB(){
    9 product.Add("部件Y");
    10 }

    11 @override
    12 public Product GetResult(){
    13 return product;
    14 } 15}

              Director类:指挥者类。

    1 public class Director{
    2     public void Construct(Builder builder){
    3         builder.BuildPartA();
    4 builder.BuildPartB(); 5 } 6 }

             客户端代码,客户不知道具体的建造过程。

    1 public static void Main(String[] args) {
    2     Director director = new Director();
    3 Builder b1 = new ConcreteBuilder1();
    4 Builder b2 = new ConcreteBuilder2();

    5 director.Construct(b1);
    6 Product p1 = b1.GetResult();
    7 p1.Show();

    8 director.Construct(b2);

    9 Product p2 = b2.GetResult();
    10 p2.Show();
    11}

    三、使用场景

          1、需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。

          2、需要生成的产品对象的属性相互依赖,需要指定其生成顺序。

          3、对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。   

          4、隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

    四、使用总结

          1、建造者模式优点: 

               1)  在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

               2)每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合 "开闭原则"。

               3)可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

          2、建造者模式缺点:

               1)  建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。

               2)如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加系统的理解难度和运行成本。

    五、典型应用

           1java.lang.StringBuilder 中的建造者模式

                StringBuilder 的继承实现关系如下图 5-1 所示

           

    图 5-1 

                Appendable 接口如下:

    1  public interface Appendable {
    2    Appendable append(CharSequence csq) throws IOException;
    3    Appendable append(CharSequence csq, int start, int end) throws IOException;
    4    Appendable append(char c) throws IOException;
    5 }

              StringBuilder 中的 append 方法使用了建造者模式,不过装配方法只有一个,并不算复杂,append 方法返回的是 StringBuilder 自身 

    1   public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
    2    @Override
    3    public StringBuilder append(String str) {
    4        super.append(str);
    5        return this;
    6    }
    7    // ...省略...
    8 }

              StringBuilder 的父类 AbstractStringBuilder 实现了 Appendable 接口

    1   abstract class AbstractStringBuilder implements Appendable, CharSequence {
    2    char[] value;
    3    int count;

    4    public AbstractStringBuilder append(String str) {
    5        if (str == null)
    6            return appendNull();
    7        int len = str.length();
    8        ensureCapacityInternal(count + len);
    9        str.getChars(0, len, value, count);
    10       count += len;
    11       return this;
    12   }

    13   private void ensureCapacityInternal(int minimumCapacity) {
    14       // overflow-conscious code
    15       if (minimumCapacity - value.length > 0) {
    16           value = Arrays.copyOf(value,newCapacity(minimumCapacity));
    17       }
    18   }
    19   // ...省略...
    20 }

              这里可以看出,Appendable 为抽象建造者,定义了建造方法,StringBuilder 既充当指挥者角色,又充当产品角色,又充当具体建造者,建造方法的实现由 AbstractStringBuilder 完成,而 StringBuilder 继承了 AbstractStringBuilder。

           2、myBatis 中的建造者模式

       org.apache.ibatis.session 包下的 SqlSessionFactoryBuilder 类,如下图 5-2 所示:

    图 5-2

             里边很多重载的 build 方法,返回值都是 SqlSessionFactory,除了最后两个所有的 build最后都调用下面这个 build 方法:

    1   public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    2       SqlSessionFactory var5;
    3       try {
    4           XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
    5           var5 = this.build(parser.parse());
    6       } catch (Exception var14) {
    7           throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
    8       } finally {
    9           ErrorContext.instance().reset();
    10          try {
    11              reader.close();
    12          } catch (IOException var13) {
    13              
    14          }
    15      }
    16      return var5;
    17  }

              其中最重要的是 XMLConfigBuilder 的 parse 方法,代码如下:

    1   public class XMLConfigBuilder extends BaseBuilder {
    2    public Configuration parse() {
    3        if (this.parsed) {
    4            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    5        } else {
    6            this.parsed = true;
    7            this.parseConfiguration(this.parser.evalNode("/configuration"));
    8            return this.configuration;
    9        }
    10   }

    11   private void parseConfiguration(XNode root) {
    12       try {
    13           Properties settings = this.settingsAsPropertiess(root.evalNode("settings"));
    14           this.propertiesElement(root.evalNode("properties"));
    15           this.loadCustomVfs(settings);
    16           this.typeAliasesElement(root.evalNode("typeAliases"));
    17         this.pluginElement(root.evalNode("plugins"));
    18           this.objectFactoryElement(root.evalNode("objectFactory"));
    19           this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    20           this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
    21           this.settingsElement(settings);
    22           this.environmentsElement(root.evalNode("environments"));
    23           this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    24           this.typeHandlerElement(root.evalNode("typeHandlers"));
    25           this.mapperElement(root.evalNode("mappers"));
    26       } catch (Exception var3) {
    27           throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
    28       }
    29   }
    30   // ...省略...
    31 }

       parse 方法最终要返回一个 Configuration 对象,构建 Configuration 对象的建造过程都在 parseConfiguration 方法中,这也就是 Mybatis 解析 XML配置文件 来构建 Configuration对象的主要过程

      参考:

       1、https://mp.weixin.qq.com/s?__biz=MzI1NDU0MTE1NA==&mid=2247483712&idx=1&sn=1ffd9837eb9413dde74ff509bf69ecc5&chksm=e9c2ed4ddeb5645b8cbf64c83d103a859ae49921c60e17fe8bebe63c26b04966be101d598848&scene=0#rd

       2、大话设计模式。

  • 相关阅读:
    结构体数组
    关于VCL的编写 (一) 如何编写自己的VCL控件
    谈一下怎样设计Oracle 分区表
    c++截取屏幕图片并保存(函数代码实现)
    微信公众平台开发之微团购
    怎么调用系统通讯录并向被选中联系人发送短信
    TFS(Team Foundation Server)介绍和入门
    2014百度之星资格赛题解
    C语言中volatilekeyword的作用
    自己定义滑动开关控件的实现与使用
  • 原文地址:https://www.cnblogs.com/ITBlock/p/10090449.html
Copyright © 2020-2023  润新知