• 设计模式之建造者模式


    定义

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

    结构

    • Product,被构建的复杂产品,一般包含多个部件。
    • Builder,建造者接口,定义了构建复杂对象的多个部件的方法。
    • ProductBuilder,具体建造者,实现了建造者接口。
    • Director,指挥者,负责安排复杂对象的构建顺序。

    简单实现

    具体产品,包含3个部件

    public class Product {
    
      private String partA;
      private String partB;
      private String partC;
    
      public void setPartA(String partA) {
        this.partA = partA;
      }
    
      public void setPartB(String partB) {
        this.partB = partB;
      }
    
      public void setPartC(String partC) {
        this.partC = partC;
      }
    
      public void show() {
        System.out.println("partA: " + partA + ",partB: " + partB + ",partC: " + partC);
      }
    }
    

    建造者接口

    /**
     * 建造者接口
     */
    public interface Builder {
    
      void buildPartA(String partA);
    
      void buildPartB(String partB);
    
      void buildPartC(String partC);
    
      Product getResult();
    }
    

    具体建造者

    /**
     * 具体建造者
     */
    public class ProductBuilder implements Builder {
    
      private Product product = new Product();
    
      @Override
      public void buildPartA(String partA) {
        product.setPartA(partA);
      }
    
      @Override
      public void buildPartB(String partB) {
        product.setPartB(partB);
      }
    
      @Override
      public void buildPartC(String partC) {
        product.setPartC(partC);
      }
    
      @Override
      public Product getResult() {
        return product;
      }
    
    }
    

    指挥者

    /**
     * 指挥者
     */
    public class Director {
    
      private Builder builder;
    
      public Director(Builder builder) {
        this.builder = builder;
      }
    
      /**
       * 真正构建
       */
      public Product construct(String partA, String partB, String partC) {
        builder.buildPartA(partA);
        builder.buildPartB(partB);
        builder.buildPartC(partC);
        return builder.getResult();
      }
    
    }
    

    客户端

    public class Client {
    
      public static void main(String[] args) {
        Builder builder = new ProductBuilder();
        Director director = new Director(builder);
        Product product = director.construct("AAA", "BBB", "CCC");
        product.show();
      }
    
    }
    

    一般情况下,我们会使用静态内部类的方法来实现建造者模式,在一个产品类内部自动带有一个具体建造者,不再需要建造者接口和指挥者,这样使建造者模式更加简洁。

    public class Product {
    
      private String partA;
      private String partB;
      private String partC;
    
      private Product(ProductBuilder builder) {
        this.partA = builder.partA;
        this.partB = builder.partB;
        this.partC = builder.partC;
      }
    
      public static ProductBuilder builder() {
        return new ProductBuilder();
      }
    
      public void show() {
        System.out.println("partA: " + partA + ",partB: " + partB + ",partC: " + partC);
      }
    
      /**
       * 具体建造者
       */
      public static class ProductBuilder {
    
        private String partA;
        private String partB;
        private String partC;
    
        public ProductBuilder partA(String partA) {
          this.partA = partA;
          return this;
        }
    
        public ProductBuilder partB(String partB) {
          this.partB = partB;
          return this;
        }
    
        public ProductBuilder partC(String partC) {
          this.partC = partC;
          return this;
        }
    
        public Product build() {
          return new Product(this);
        }
    
      }
    }
    

    客户端代码如下

    public class Client {
    
      public static void main(String[] args) {
        Product product = Product.builder()
            .partA("aaa")
            .partB("bbb")
            .partC("ccc")
            .build();
        product.show();
      }
    
    }
    

    建造者模式在JDK和Guava中的实现

    JDK中实现

    JDK中构建字符串的建造者StringBuilder

    public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence {
        ...
        public StringBuilder append(Object obj) {
            return append(String.valueOf(obj));
        }
        ...
        public String toString() {
            // Create a copy, don't share the array
            return new String(value, 0, count);
        }
    }
    

    客户端使用

    public class TestStringBuilder {
    
      public static void main(String[] args) {
        String result = new StringBuilder()
            .append(12)
            .append(true)
            .append("abc")
            .toString();
        System.out.println(result);
      }
    
    }
    

    Guava中实现

    Guava中缓存的实现CacheBuilder

    public final class CacheBuilder<K, V> {
        public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
        checkState(
            expireAfterWriteNanos == UNSET_INT,
            "expireAfterWrite was already set to %s ns",
            expireAfterWriteNanos);
        checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
        this.expireAfterWriteNanos = unit.toNanos(duration);
        return this;
      }
      public CacheBuilder<K, V> initialCapacity(int initialCapacity) {
        checkState(
            this.initialCapacity == UNSET_INT,
            "initial capacity was already set to %s",
            this.initialCapacity);
        checkArgument(initialCapacity >= 0);
        this.initialCapacity = initialCapacity;
        return this;
      }
      public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
        checkWeightWithWeigher();
        checkNonLoadingCache();
        return new LocalCache.LocalManualCache<>(this);
      }
    }
    

    客户端使用

    import com.google.common.cache.Cache;
    import com.google.common.cache.CacheBuilder;
    import java.util.concurrent.TimeUnit;
    
    public class TestCacheBuilder {
    
      public static void main(String[] args) {
        Cache<String, String> cache = CacheBuilder.newBuilder()
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .initialCapacity(30)
            .softValues()
            .recordStats()
            .build();
        System.out.println(cache);
      }
    
    }
    

    Guava中不可变集合的实现

    import com.google.common.collect.ImmutableList;
    
    public class TestImmutableList {
    
      public static void main(String[] args) {
        ImmutableList<String> list = ImmutableList.<String>builder()
            .add("aaa")
            .add("bbb")
            .add("ccc")
            .build();
        System.out.println(list);
      }
    
    }
    

    总结

    优点

    1. 将产品的构建过程和表现分离,耦合度低,方便扩展。
    2. 可以更加精细的控制产品的创建过程。

    缺点

    1. 如果产品的内部结构复杂多变,当产品内部发生变化,建造者也要同步修改,后期维护成本较大。

    本质

    建造者模式的本质就是分离整体构建算法和部件构造。

    使用场景

    1. 需要创建的产品对象内部结构比较复杂,需要分离构建过程和使用,这种情况下可以考虑使用建造者模式。

    参考

    大战设计模式【17】—— 建造者模式
    设计模式(六)——建造者模式(源码StringBuilder分析)
    设计模式的征途—6.建造者(Builder)模式
    研磨设计模式-书籍

  • 相关阅读:
    BOS13——quartz定时任务,Highcharts前端图表的使用
    BOS12——多对多添加方法,多对多页面需要字段问题(不多的话直接提供get方法),修改Realm中授权方法(查询数据库),缓存Java对象的方法,加载左侧菜单(ztree提供pId)
    BOS10——权限控制的实现,apache shiro权限管理框架的使用,参数同名问题,EasyUI的combotree的使用
    BOS08——Web工程中的CXF客户端,加载select框中的内容,select框移动,提交时将select全部选中,CRM中更新的方法,别名的用于不用
    CXF——WebService简介,CXF框架的使用
    BOS06——带有过滤条件的查询(解决form表单提交时,分页携带过滤条件困难的问题)and连表查询返回数据不标准问题,文件导出,BaseDao扩展一个离线Criteria查询,前端字段名重复问题(不知道对应那个字段了),多张表保存问题
    Python基础之文件处理
    Python基础之字符编码
    Python基础之数据类型
    Python安装
  • 原文地址:https://www.cnblogs.com/strongmore/p/15130599.html
Copyright © 2020-2023  润新知