构造函数参数多时使用builder模式

3,145 阅读4分钟

我们平时新建一个Java类的第一步要做的就是编写她的构造函数,但是对于不同的需求,我们不应该仅仅知道最基本的构造函数编写方式,也应该了解一下针对不同需求或特征是否存在更好的构造方式:

1. 静态工厂方法

类可以通过构造函数创建新对象,但是也可以通过静态工厂方法去创建新对象,静态工厂方法指的是一个类中的静态方法,该方法可以返回一个属于该类的实例;我们先看JDK中boolean类中的一个静态工厂方法的实现:

    public static Boolean valueOf(String s) {
        return toBoolean(s) ? TRUE : FALSE;
    }

    Boolean bTrue = Boolean.valueOf("true");    //创建对象

静态工厂方法的优势: (1) 可读性更强 构造器必须和类名相同,构造不同的对象只能通过参数的不同来实现;但是通过静态工厂方法,我们可以根据创建对象的不同特征来命名我们的函数,增加程序的可读性。 (2)不必每次调用时都创建一个新的对象 静态工厂方法能够将构建好的对象缓存起来,重复利用;如果该对象是个大对象,创建的陈本较高,静态工厂方法将会极大地提升性能;并且,在某些不可变类或者单例模式的类中,静态工厂方法更加方便保证对象只有一个。 (3)更方便控制实例创建的时间 当我们的类中包含静态变量时,每当使用到该变量时都会引起该类的构造函数,可能此时我们还不想去实例化该类,控制起来比较麻烦;但是使用静态工厂方法实例化对象后,类的实例化只发生在静态工厂方法被调用后,所以使得实例创建的时间更加可控。 (4)可以返回子类对象 通常构造函数只能创建该类型的实例,但是静态工厂方法却能够产生子类实例,在我们选择返回对象时具有更大的灵活性。 (5)代码更简洁 当构造函数需要的参数较多时,可以利用编译器的“类型推导”替我们找到刹那参数类型:

public static <K,V> Hashmap<K,V> newInstance(){
    return new HashMap<K,V>();
}

Map<String,Object> map = HashMap.newInstance();

静态工厂方法的缺点: (1)类如果不包含公有、保护的构造方法,将不能被子类实例化; (2)静态工厂方法与其他静态方法没有实质的区别。

2. 多参数时的构造函数

静态工厂方法和构造器都有一个局限性:不能很好地扩展大量的可选参数,当构造函数需要包括大量的可选参数时,不仅构造函数会变得十分长,如果参数中有几个类型相同的参数,开发者一不小心就可能会填错,并且很难发现这个错误。下面我们介绍一种builder模式来代替构造函数:

public class Student {
    private String name;
    private int stuNum;
    private int age;
    private int classNum;
    private int height;
    private int weight;

    public Student(Builder builder) {
        this.name = builder.name;
        this.stuNum = builder.stuNum;
        this.age = builder.age;
        this.classNum = builder.classNum;
        this.height = builder.height;
        this.weight = builder.weight;
    }

    public static class Builder{
        //必有的
        private String name;
        private int stuNum;
        //可选的
        private int age;
        private int classNum;
        private int height;
        private int weight;

        public Builder(String name, int stuNum) {
            this.name = name;
            this.stuNum = stuNum;
        }
        public Builder age(int val){
            age = val;
            return this;  //返回该完整实例,方便后面的函数继续设置属性值
        }
        public Builder classNum(int val){
            classNum = val;
            return this;
        }
        public Builder height(int val){
            height = val;
            return this;
        }
        public Builder weight(int val){
            weight = val;
            return this;
        }

        //最终build()函数调用类的构造函数,并将builder传入
        public Student build(){
            return new Student(this);
        }
    }
}

由代码可以看出,类中增加一个静态内部类Builder,Builder的构造函数中只填必选的参数,可选的参数通过类似setter()函数对属性赋值,并且在方法的最后返回该实例,这样可以构成链式的参数配置方法:

    public static void main(String[] args) {
        Student student = new Student.Builder("miles",123456).age(23).classNum(3).build();
    }

由上面代码可以看出,可以使用静态内部类Builder的方法build()方法创建Student对象,并且是通过链式的方法设置属性,十分便于可选参数的设置,并且可读性也更强。