• 《设计模式之美》


    46篇 建造者模式

    Builder 模式,中文翻译为建造者模式或者构建者模式,也有人叫它生成器模式。建造者模式的原理和实现比较简单,重点是掌握应用场景,避免过度使用。如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 set() 方法来解决。但是,如果存在下面情况中的任意一种,我们就要考虑使用建造者模式了。

    • 我们把类的必填属性放到构造函数中,强制创建对象的时候就设置。如果必填的属性有很多,把这些必填属性都放到构造函数中设置,那构造函数就又会出现参数列表很长的问题。如果我们把必填属性通过 set() 方法设置,那校验这些必填属性是否已经填写的逻辑就无处安放了。
    • 如果类的属性之间有一定的依赖关系或者约束条件,我们继续使用构造函数配合 set() 方法的设计思路,那这些依赖关系或约束条件的校验逻辑就无处安放了。
    • 如果我们希望创建不可变对象,也就是说,对象在创建好之后,就不能再修改内部的属性值,要实现这个功能,我们就不能在类中暴露 set() 方法。构造函数配合 set() 方法来设置属性值的方式就不适用了。

    建造者模式举例:

    public class ResourcePoolConfig {
      private String name;
      private int maxTotal;
      private int maxIdle;
      private int minIdle;
    
      private ResourcePoolConfig(Builder builder) {
        this.name = builder.name;
        this.maxTotal = builder.maxTotal;
        this.maxIdle = builder.maxIdle;
        this.minIdle = builder.minIdle;
      }
      //...省略getter方法...
    
      //我们将Builder类设计成了ResourcePoolConfig的内部类。
      //我们也可以将Builder类设计成独立的非内部类ResourcePoolConfigBuilder。
      public static class Builder {
        private static final int DEFAULT_MAX_TOTAL = 8;
        private static final int DEFAULT_MAX_IDLE = 8;
        private static final int DEFAULT_MIN_IDLE = 0;
    
        private String name;
        private int maxTotal = DEFAULT_MAX_TOTAL;
        private int maxIdle = DEFAULT_MAX_IDLE;
        private int minIdle = DEFAULT_MIN_IDLE;
    
        public ResourcePoolConfig build() {
          // 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等
          if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("...");
          }
          if (maxIdle > maxTotal) {
            throw new IllegalArgumentException("...");
          }
          if (minIdle > maxTotal || minIdle > maxIdle) {
            throw new IllegalArgumentException("...");
          }
    
          return new ResourcePoolConfig(this);
        }
    
        public Builder setName(String name) {
          if (StringUtils.isBlank(name)) {
            throw new IllegalArgumentException("...");
          }
          this.name = name;
          return this;
        }
    
        public Builder setMaxTotal(int maxTotal) {
          if (maxTotal <= 0) {
            throw new IllegalArgumentException("...");
          }
          this.maxTotal = maxTotal;
          return this;
        }
    
        public Builder setMaxIdle(int maxIdle) {
          if (maxIdle < 0) {
            throw new IllegalArgumentException("...");
          }
          this.maxIdle = maxIdle;
          return this;
        }
    
        public Builder setMinIdle(int minIdle) {
          if (minIdle < 0) {
            throw new IllegalArgumentException("...");
          }
          this.minIdle = minIdle;
          return this;
        }
      }
    }
    
    // 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
    ResourcePoolConfig config = new ResourcePoolConfig.Builder()
            .setName("dbconnectionpool")
            .setMaxTotal(16)
            .setMaxIdle(10)
            .setMinIdle(12)
            .build();
    

     

    lombok中的@Builder支持构造者模式。@Builder提供了一种比较推崇的构建值对象的方式,非常推荐的一种构建值对象的方式。缺点就是父类的属性不能产于builder。

    @Builder
    public class Demo {
        private final int finalVal = 10;
    
        private String name;
        private int age;
    }
    
    public static void main(String[] args) {
            Demo demo = Demo.builder().name("aa").age(10).build();
            System.out.println(demo); 
    }
    

      使用@Builder后,就没有了无参构造函数。若需要,可以自己写构造函数。比如

    @Builder
    public class Demo {
        private final int finalVal = 10;
    
        private String name;
        private int age;
    
        public Demo() {}
    
        public Demo(String name, int age) {
            this.name = name;
            this.age = age;
        }    
    }
    

      或者可以使用@Tolerate注解 

    @Builder
    public class Demo {
        private final int finalVal = 10;
    
        private String name;
        private int age;
    
        @Tolerate
        public Demo() {}  
    }
    

      

     
  • 相关阅读:
    Linux 普通用户su命令切换控制
    Linux上的文件管理类命令(2)
    系统内存管理
    ssh 安全配置
    redhat系统安装部署
    Unity截屏
    Unity场景道具模型拓展自定义编辑器
    Unity优化之减少Drawcall
    Unity安卓连接profile调试
    Unity游戏数据用Json保存
  • 原文地址:https://www.cnblogs.com/sunada2005/p/14356346.html
Copyright © 2020-2023  润新知