Java 解决构造方法参数过多-builder模式(effect java 学习笔记2)

1、前景:

  通常状况咱们不会遇到这样的状况,使用静态工厂方法,或者构造方法就足够。可是它们也有一个限制就是,它们不能很好的扩展到不少可选参数的场景。随着咱们业务的深刻,某些java bean 中的参数将会愈来愈多,咱们添加的构造方法也相应的增长。想一想一个10个参数的构造方法,我胃痛。java

  既然想要用builder模式,咱们首先须要知道传统方法的不足。程序员


2、可伸缩构造方法 VS builder模式

  咱们都用代码实例来讲话安全

一、可伸缩构造方法

public class Student {
    private final String name; // required
    private final String sex;  // required
    private final int weight;  // optional
    private final int height;  // optional 
    private final int age;     // optional

    public Student(String name, String sex) {
        this(name, sex, 0);
    }
    
    public Student(String name, String sex, int w) {
        this(name, sex, w, 0);
    }
    
    public Student(String name, String sex, int w, int h) {
        this(name, sex, w, h, 0);
    }

    public Student(String name, String sex, int w, int h, int a) {
        this.name = name;
        this.sex = sex;
        this.weight = w;
        this.height = h;
        this.age = a;
    }
}
复制代码

当咱们想建立一个Student实例的时候,能够设置全部参数的最短的够着方法以下:bash

Student student = new Student("小明", "男", 50, 150, 16);微信

  一般状况下,这个构造方法可能须要许多你不想设置的参数(是否是有点不爽),随着参数的不断增长,它很快会失控的。(你也会发疯的)。首先咱们很难读懂这个方法,其次若是反转了两个参数,编译器是不会报错的。好比身高和体重填反了,糟心。。。。。性能

二、JavaBean模式

  当在构造方法中遇到许多可选参数时,另外一种选择是 JavaBeans 模式,在这种模式中,调用一个无参数的构造函 数来建立对象,而后调用 setter 方法来设置每一个必需的参数和可选参数:ui

public class Student {
    private  String name; // required
    private  String sex;  // required
    private  int weight;  // optional
    private  int height;  // optional
    private  int age;     // optional

    public Student() {}


    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
复制代码

这种模式没有伸缩构造方法的缺点。有点冗长,但建立实例容易,而且容易阅读this

Student student = new Student();
        student.setName("小明");
        student.setSex("男");
        student.setAge(16);
        student.setWeight(50);
        student.setHeight(150);
复制代码

  JavaBeans 模式自己有严重的缺陷。因为构造方法在屡次调用中被分割,因此在构造过程当中 JavaBean 可能处于不一致的状态。该类没有经过检查构造参数参数的有效性来执行一致性的选项。在不一致的状态下尝试使用 对象可能会致使与包含 bug 的代码截然不同的错误,所以很难调试。一个相关的缺点是,JavaBeans 模式排除了让类 不可变的可能性,而且须要在程序员的部分增长工做以确保线程安全spa

三、builder模式

  builder 模式结合了可伸缩构造方法模式的安全性和JavaBean模式的可读性。线程

public class Student {
    private final String name;
    private final String sex;
    private  final int weight;
    private final int height;
    private  final int age;

    private Student(Builder builder) {
        this.name = builder.name;
        this.sex = builder.sex;
        this.weight = builder.weight;
        this.height = builder.height;
        this.age = builder.age;
    }
    
    public static class Builder {
        private final String name; // required
        private final String sex;  // required
        private int weight;  // optional
        private int height;  // optional
        private int age;     // optional

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

        public Builder setWeight(int weight) {
            this.weight = weight;
            return this;
        }

        public Builder setHeight(int height) {
            this.height = height;
            return this;
        }
        
        public Builder setAge(int age) {
            this.age = age;
            return this;
        }
        
        public Student build() {
            return new Student(this);
        }

    }
}
复制代码

  我首先来喷一下,代码量翻倍了。可是Student 类是不可变的,全部的参数默认值都在一个地方。builder 的 setter 方法返回 builder 自己, 这样调用就能够被连接起来,从而生成一个流畅的 API。实例以下:

Student student = new Student.Builder("小明", "男").setWeight(50)
                .setHeight(150).setAge(16).build();
复制代码

  代码很容易编写,更重要的是易于阅读。 Builder 模式模拟 Python 和 Scala 中的命名可选参数。 这里没有涉及到有效性的检查


总结:

  builder 对构造方法的一个微小的优点是,builder 能够有多个可变参数,由于每一个参数都是在它本身的方法中指 定的。

  Builder 模式很是灵活。 单个 builder 能够重复使用来构建多个对象。 builder 的参数能够在构建方法的调用之间 进行调整,以改变建立的对象。 builder 能够在建立对象时自动填充一些属性,例如每次建立对象时增长的序列号。

  Builder 模式也有缺点。为了建立对象,首先必须建立它的 builder。虽然建立这个 builder 的成本在实践中不太可 能被注意到,但在性能关键的状况下可能会出现问题。并且,builder 模式比伸缩构造方法模式更冗长,所以只有在 有足够的参数时才值得使用它,好比四个或更多。可是请记住,若是但愿在未来添加更多的参数。可是,若是从构造 方法或静态工厂开始,并切换到 builder,当类演化到参数数量失控的时候,过期的构造方法或静态工厂就会面临尴 尬的处境。所以,因此,最好从一开始就建立一个 builder。

  总而言之,当设计类的构造方法或静态工厂的参数超过几个时,Builder 模式是一个不错的选择,特别是若是许 多参数是可选的或相同类型的。客户端代码比使用伸缩构造方法(telescoping constructors)更容易读写,而且 builder 比 JavaBeans 更安全。

ps:若是有微信读书的书友,能够来微信读书群传送门找组织。

相关文章
相关标签/搜索