《一天一模式》— 建造者模式

1、建造者模式的概念

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于建立型模式,它提供了一种建立对象的最佳方式。 java

2、何时使用建造者模式

简单来讲,建造者模式经过一步步的设置(构建)对象的值,最终构建了一个对象。设计模式

经常使用场景以下:数组

  • 经过步骤来建立对象,一步步将多个值装配到一个对象中;
  • 灵活配置类的数据,可自定义顺序;
  • 初始化一个对象时,参数过多,不方便用构造函数,可读性差;
  • 初始化一个对象时,参数组合灵活,不方便用构造函数;

3、怎么使用建造者模式

3.1 不适用建造者模式的弊端

好比一个对象的参数过多,经过构造函数来建立,很是繁琐切可读性差,例以下面的伪代码:并发

public class Obj {

    public Obj(10个参数) { ... }

}

// 使用
Obj obj = new Obj(1,2,3,4,5,6,7,8,9,10);

写起来麻烦,读起来不清晰,要记得第几个参数表明那个字段,通常超过3个参数就不太好记了。ide

此外,Sonarlint等代码质量检测工具也会把这种长参数的构造函数定义为坏味道。函数

还有,就是构件对象特别灵活,例以下面伪代码:工具

public class Obj {
    
    public Obj(int a, int b) { ... }

    public Obj(int a, float c) { ... }

    public Obj(int b, double d) { ... }

    ....

}

这种不一样参数列表的构造函数,写起来也很复杂,读起来很困难。以上的状况均可以用建造者模式去解决。ui

3.2 建造者模式的实现方式

定义一个可使用建造者模式的需求,而后用Java语言来实现。this

例如,要开发一个表明Http返回值的业务对象,这个对象须要4个属性:spa

  • 业务状态码:code;
  • 业务状态码描述:desc;
  • 返回消息:msg;
  • 返回数据:data;

每次返回时,要求code和desc是必填项,msg和data为选填项(可都不返回,可只返回一个,或者返回两个)。

下面用建造者模式来建立这个对象:

代码以下:

public class HttpResult<T> {

    /**
     * 构造函数。
     */
    private HttpResult() {
    }

    /**
     * 构造函数。
     *
     * @param builder 建造者。
     */
    private HttpResult(Builder<T> builder) {
        this.code = builder.status.getCode();
        this.desc = builder.status.getDesc();
        this.msg = builder.msg;
        this.data = builder.data;
    }

    /**
     * @return 得到返回代码值。
     */
    public int getCode() {
        return code;
    }

    /**
     * @return 得到返回代码描述。
     */
    public String getDesc() {
        return desc;
    }

    /**
     * @return 得到响应消息。
     */
    public String getMsg() {
        return msg;
    }

    /**
     * @return 得到响应数据。
     */
    public T getData() {
        return data;
    }

    /**
     * @return 重写toString()方法。
     */
    @Override
    public String toString() {
        return "HttpResult{" +
                "code=" + code +
                ", desc='" + desc + '\'' +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }

    /**
     * HttpResult的构造器。
     *
     * @author xuepeng
     */

    public static class Builder<K> {

        /**
         * 构造函数。
         *
         * @param status 返回状态。
         */
        public Builder(HttpResultStatus status) {
            this.status = status;
        }

        /**
         * 设置返回消息。
         *
         * @param msg 返回消息。
         * @return HttpResult.Builder对象。
         */
        public Builder<K> msg(String msg) {
            this.msg = msg;
            return this;
        }

        /**
         * 设置返回数据。
         *
         * @param data 返回数据。
         * @return HttpResult.Builder对象。
         */
        public Builder<K> data(K data) {
            this.data = data;
            return this;
        }

        /**
         * 建立HttpResultEntity对象。
         *
         * @return HttpResultEntity对象。
         */
        public HttpResult<K> build() {
            return new HttpResult<>(this);
        }

        /**
         * @return 重写toString()方法。
         */
        @Override
        public String toString() {
            return "Builder{" +
                    "status=" + status +
                    ", msg='" + msg + '\'' +
                    ", data=" + data +
                    '}';
        }

        /**
         * 返回状态。
         */
        private HttpResultStatus status;
        /**
         * 返回消息。
         */
        private String msg;
        /**
         * 返回数据。
         */
        private K data;

    }

    /**
     * 返回代码值。
     */
    private int code;
    /**
     * 返回代码描述。
     */
    private String desc;
    /**
     * 返回消息。
     */
    private String msg = StringUtils.EMPTY;
    /**
     * 返回数据。
     */
    private T data;

}

上面类就是一个HttpResult的对象,经过建造者模式去建立,主要作了以下事情:

  • 屏蔽了public的构造函数;
  • 定义了一个private的构造函数,便于给内部的建造者调用,入参是建造者对象(也就是说,在建造者构件完毕后,会new一个HttpResult,并发建造者本身传递给HttpResult,HttpResult取建造者中的数据初始化本身的字段);
  • 定义了一个内部静态类Builder,构造函数是需求中说的返回码(必填项);
  • 定义了几个链式调用的方法,msg和data,能够随意设置(选填项);
  • 定义了一个build方法,在设置好数据后在调用该方法,方法调用HttpResult的private的构造函数,建立对象;

上面就是建造者模式的几个核心点,建造者模式的使用方式以下:

// 填写所有参数
public static <T> HttpResult<T> success(String msg, T data) {
        return new HttpResult.Builder<T>(SUCCESS)
                             .msg(msg)
                             .data(data)
                             .build();
}

// 填写1个可选参数
public static <T> HttpResult<T> success(String msg, T data) {
        return new HttpResult.Builder<T>(SUCCESS)
                             .msg(msg)
                             .build();
}

// 不填写可选参数
public static <T> HttpResult<T> success(String msg, T data) {
        return new HttpResult.Builder<T>(SUCCESS).build();
}
  • 经过new一个HttpResult.Builder来建立一个建造者,构造函数是返回码(code, desc,这里作成了一个枚举对象);
  • 而后能够选择性的调用msg()或者data()去设置HttpResult的可选字段;
  • 最后,调用build()来建造一个HttpResult;

4、总结

建造者模式的好处:

  • 可读性高:解决了构造函数参与列表过长的问题,并经过链式调用方式来建造对象,代码可读性高;
  • 扩展性强:当有新的参数须要设置时,只添加方法便可丰富链式调用的设置方法;

建造者模式与其余用来建立对象的设计模式的不一样点在于,它关注的是经过一步步的构建来建立一个对象,且对象的步骤能够随意改变

以上就是我对建造者模式的一些理解,有不足之处请你们指出,谢谢。

相关文章
相关标签/搜索