设计模式-建造者模式

适用场景

如果一个类中有很多属性,为了避免构造函数的参数列表过长,影响代码的可读性和易用性,我们可以通过构造函数配合 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的内部类。

        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;
            }
        }
    }

    public static void main(String[] args) {
        // 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
        ResourcePoolConfig config = new ResourcePoolConfig.Builder()
                .setName("dbconnectionpool")
                .setMaxTotal(16)
                .setMaxIdle(10)
                .setMinIdle(12)
                .build();
    }
}

实际上,如果我们并不是很关心对象是否有短暂的无效状态也不是太在意对象是否是可变的。比如,对象只是用来映射数据库读出来的数据,那我们直接暴露 set() 方法来设置类的成员变量值是完全没问题的。而且,使用建造者模式来构建对象,代码实际上是有点重复的,ResourcePoolConfig 类中的成员变量,要在 Builder 类中重新再定义一遍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值