我们平时新建一个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对象,并且是通过链式的方法设置属性,十分便于可选参数的设置,并且可读性也更强。