2.遇到多个构造器参数时要考虑使用构建器

当一个类有很多个成员变量时,如果我们还是采用构造器传参的方式创建对象,我们就需要一次性传很多参数。

如果提供的构造方法参数中包含了我们不想设置的参数,但是我们不得不为它传递值。

如下:

//姓名、年龄、性别、身高、爱好。。。。(即使 身高 未知,我们也不得不在此处传递一个""占位)
//当参数越来越多,将无法维护,一不留神穿错参数,或者顺序颠倒无法快速定位错误位置。
new User("张三","18","男","","打游戏");

接下来介绍两种替代方案:

第一种(JavaBeans模式):使用无参构造方法创建对象,再使用set方法来设置每个必要参数。

User user = new User();
user.setName("张三");
user.setAge("18");
...

这种方式的好处在于:我们创建对象变得很方便,并且我们只需要关注我们需要设置参数,为其设置值。

但是这种方式存在一个弊端:创建对象的整个过程被拆分了,在构造过程中JavaBean可能存在不一致的状态。另一点就是JavaBeans模式使得把类做成不可变的可能性不复存在。

第二种 (建造者模式):既能保证安全性又能保证可读性。

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

通过代码帮助我们理解

package lesson2;

/**
 * @Description: user
 * @author: caoshenyang
 * @date: 2020.12.22
 */
public class User {

    private String username;
    private String age;
    private String gender;
    private String hobby;

    /**
     * 构建器
     */
    public static class Builder {

        // 必须的参数
        private String username;
        private String age;
        // 可选的参数 可以在这里设置默认值
        private String gender = "保密";
        private String hobby;

        public Builder(String username, String age) {
            this.username = username;
            this.age = age;
        }

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

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

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

    private User(Builder builder) {
        username = builder.username;
        age = builder.age;
        gender = builder.gender;
        hobby = builder.hobby;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age='" + age + '\'' +
                ", gender='" + gender + '\'' +
                ", hobby='" + hobby + '\'' +
                '}';
    }
}

User的构造器私有的,所有的参数都放在Builder里,builder的设置方式返回的是Builder本身,这样便于把调用链接起来,得到一个流式的API。

客户端代码:

/**
 * @Description: 客户端
 * @author: caoshenyang
 * @date: 2020.12.23
 */
public class Client {

    public static void main(String[] args) {
        User build = new User.Builder("张三", "12").gender("男").hobby("打游戏").build();
        System.out.println(build);
    }
}

运行结果:

User{username='张三', age='12', gender='男', hobby='打游戏'}

Builder模式模拟了具名的可选参数,这样客户端编写代码变得更容易,并且可读性更好。

Builder模式同时也试用于类层次结构

使用平行层次结构的builder时,各自嵌套在相应的类中。抽象类有抽象的builder,具体类有具体的builder。

优点:

  1. builder(构建器)可以有多个可变参数,因为builder是利用单独的方法来设置每一个参数。
  2. 可以将多次调用传入的参数集中到一个域中。
  3. 十分灵活,利用单个builder可以创建多个对象。
  4. 参数可以在调用期间调整
  5. 可以自动填充某些域,比如创建某个类时自动增加序号

缺点:

  1. 创建对象时必须先创建它的构建器,在极度追求性能的环境下会成为问题。
  2. 代码更加冗长,适合参数比较多的时候使用。(作者建议4个以上)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容