美文网首页
设计模式 - Builder 模式

设计模式 - Builder 模式

作者: no_today | 来源:发表于2017-10-30 20:20 被阅读0次

Effective Java 第2条:遇到多个构造器参数时要考虑使用构建器

三种创建对象的方式。

目录

  • 重叠构造器
  • JavaBeans
  • 构建器 Builder

#重叠构造器

/**
 * Create By IntelliJ IDEA.
 *
 * @Author: Cheng
 * @Date: 2017/10/30
 * @Time: 19:21
 * <p>
 * 层叠构造器
 */
public class User {
    private String name;        // required
    private String password;    // required

    private int id;             // optional
    private String email;       // optional
    private String phone;       // optional
    private String address;     // optional

    public User(String name, String password, int id, String email, String phone, String address) {
        this.name = name;
        this.password = password;
        this.id = id;
        this.email = email;
        this.phone = phone;
        this.address = address;
    }

    public User(String name, String password) {
        this(name, password, -1, null, null, null);
    }
    
    public User(String name, String password, int id) {
        this(name, password, id, null, null, null);
    }

    public User(String name, String password, int id, String email) {
        this(name, password, id, email, null, null);
    }
    
    public User(String name, String password, int id, String email, String phone) {
        this(name, password, id, email, phone, null);
    }

    // 不提供 setter 方法,该对象就是不可变的了。
}

提供第一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,依次类推,最后一个构造器包含所有可选参数。

重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且依然较难阅读。

参数一多起来不阅读文档将很难理解创建对象该传什么参数 或者将参数顺序搞乱


#JavaBeans

/**
 * Create By IntelliJ IDEA.
 *
 * @Author: Cheng
 * @Date: 2017/10/30
 * @Time: 19:21
 * <p>
 * JavaBeans
 */
public class User {
    private String name;        // required
    private String password;    // required

    private int id;             // optional
    private String email;       // optional
    private String phone;       // optional
    private String address;     // optional

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    // 省略getter and setter方法。
}

JavaBeans模式弥补了重叠构造器的不足。说的明白点,就是创建实例很容易,这样产生的代码读起来也很容易 get set

但是JavaBeans模式有一个缺点。因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态,也就是说,JavaBean是非线程安全的。

JavaBeans模式阻止了把类做成不可变的可能。set


#构建器 Builder

/**
 * Create By IntelliJ IDEA.
 *
 * @Author: Cheng
 * @Date: 2017/10/30
 * @Time: 18:34
 * <p>
 * 构建器模式
 */

/**
 * 用户类
 *
 * 帐号和密码必须输入
 * id不赋值表示未存入数据库
 * 邮箱、手机、地址为选填项
 */
public class User {
    private String name;        // required
    private String password;    // required

    private int id;             // optional
    private String email;       // optional
    private String phone;       // optional
    private String address;     // optional

    /**
     * 构造方法传入构造器
     * @param builder
     */
    private User(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.password = builder.password;
        this.email = builder.email;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    /**
     * User类的构造器
     * 选填属性设置默认值
     *
     * 必须传入的属性由构造器传入设置
     * 选填属性由方法设置
     */
    public static class Builder {
        private String name;
        private String password;

        private int id = -1;
        private String email = "未设置";
        private String phone = "未设置";
        private String address = "未设置";

        public Builder(String name, String password) {
            this.name = name;
            this.password = password;
        }

        /**
         * 返回的是建造器对象
         * @param email
         * @return
         */
        public Builder setEmail(String email) {
            this.email = email;
            return this;
        }

        public Builder setPhone(String phone) {
            this.phone = phone;
            return this;
        }

        public Builder setAddress(String address) {
            this.address = address;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }

    // 不提供 setter 方法,该对象就是不可变的了。也就是说,保证了同步性。
}

拥有重叠构造器模式的安全性,也能保证JavaBean模式那么好的代码可读性。这就是 Builder 模式的一种形式。

不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器,得到一个
builder 对象。然后客户端在 builder 对象上调用类似 setter 的方法来设置可选参数。最后调用无参的 build 方法来生成不可变的对象。

这个 builder 是它构建的类的静态成员类。

注意 User 被设计成不可变的了,所有的默认参数值都单独放在一个地方。builder 的 setter 方法返回 builder 本身,以便把调用链接起来。下面是客户端代码:

public static void main(String[] args) {
        User user = new User.Builder("cheng", "********")
                .setEmail("qq.com")
                .setPhone("110")
                .setAddress("HangZhou")
                .build();

        System.out.println(user);
}

builder 就像个构造器一样,可以对器参数强加约束条件。buld 方法可以检验这些约束条件。

public User build() {
        // 校验逻辑
        return new User(this);
}

不足

  1. 比起另外两种创建模式,Builder 模式多创建了一个构建器对象。
  2. 代码量比重叠构造器模式更加冗长。

#总结

如果类的构造器中具有多个参数,并且对安全有要求,设置这种类时,Builder 模式就是种不错的选择。

相关文章

网友评论

      本文标题:设计模式 - Builder 模式

      本文链接:https://www.haomeiwen.com/subject/ynqmpxtx.html