Java之静态工厂方法
著名Java书籍《Effective Java》中第一条就提到了一个原则:考虑用静态方法而不是构造器。初看这条规则的时候我还感到很费解,构造器是Java提供的构造对象的方法,为什么不是首选呢?
假设有这样一个类:
package com.example.demo;
public class Dog {
private String name;
private String color;
private int age;
public Dog() {
}
public Dog(String name) {
this.name = name;
}
public Dog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
}
一条狗的属性很多,比如名字,颜色和年龄,我上面的类里有三个构造器,一个无参数的默认构造器,一个参数只有name的构造器和一个有所有三个参数的构造器。
那么这个时候问题来了,我想加一个只有毛色color参数的构造器,因为确实有些狗我只知道它的颜色,但是这已经是不可能了:
public Dog(String color) {
this.color = color;
}
方法重载也是有限制的,这个构造器实际上和name构造器冲突了。
为了实现功能,我们还是改改代码的好:
package com.example.demo;
public class Dog {
private String name;
private String color;
private int age;
private Dog() {
}
public static Dog newDogWithAllParam(String name, String color, int age) {
Dog dog = new Dog();
dog.name = name;
dog.age = age;
dog.color = color;
return dog;
}
public static Dog newDogWithName(String name) {
Dog dog = new Dog();
dog.name = name;
return dog;
}
public static Dog newDogWithColor(String color) {
Dog dog = new Dog();
dog.color = color;
return dog;
}
// Getters & Setters
}
每次新建对象的时候,只需要调度需要的方法就可以了。这段代码也解释了书中提到的静态工厂方法的一个好处——有名字。通过名字我可以清楚的知道我是用什么属性去创建的对象。
我个人很喜欢使用Guava的Lists类库来创建List:
List<Long> list = Lists.newArrayList();
这种方式可以说简洁而优雅,其实,这也是静态工厂方法取代构造器的典型案例,它的源码可以来品味一下:
@GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayList() {
return new ArrayList<>();
}
其实和我之前的代码原理上是一样的。
《Effective Java》还提到了一条,就是静态工厂方法不必在每次被调用的时候都会产生新对象,照例要看源码,我们看一下书里提供的一段代码:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
在这样的语句:boolean bl = Boolean.valueOf(false); 的时候,实际上是不需要创建额外的对象的,原因在我之前写static的文章中有提及:
虽然上面的例子基本上是一句废话,但是也能说明问题。
静态工厂方法还有一个好处,就是可以返回子类型,比如我们有一个Car类,其中有一个关键的参数叫做price,我希望price>30万的返回豪车子类,price<30万的返回买菜车子类,那么代码就要这样写了:
package com.example.demo;
public class Car {
private int price;
Car() {}
public static Car newCarWithPrice(int price) {
if (price > 30 * 10000) {
return new LuxCar();
} else {
return new NormalCar();
}
}
}
这种代码就是构造器无法实现的了。