静态工厂方法的优缺点
什么是静态工厂方法
一般而言,如果一个类需要调用另一个类的变量和方法,那么该类需要先获得另一个类的实例,最常用的的方法就是被调用类提供一个公有的构造方法。但是,还要另外一种方法,就是被调用类提供一个可以返回该类实例的静态方法,该静态方法称为静态工厂方法。
例如下面的例子(引自《Effective Java》),将boolean基本类型值转换成了一个Boolean对象引用:
1 | public static Boolean valueOf(boolean b) { |
优点
和构造方法不一样,静态工厂方法可以有自己明确的名字。比如newInstance、getInstance、valueOf,可以更明确知道这些方法名字的意思。而构造方法只能通过new类名来创建,比如Person person = new Person()。
不必没次调用时都创建一个新对象。使用静态工厂方法对外提供单例,其实就是提前准备好实例,这样可以重复利用,减少重复创建实例,不过这也需要注意线程安全问题。
可以返回原返回类型的任何子类的对象。这个可以这么理解,例如EnumSet类,EnumSet是抽象类是不能被实例化的,但是可以通过里面的noneOf静态工厂方法返回它子类的对象,RegularEnumSet和JumboEnumSet都是EnumSet的子类,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable {
EnumSet(Class<E>elementType, Enum[] universe) {}
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
}在创建参数化类型实例的时候,它们使代码变得更加简洁。这条可以这么理解,比如在创建一个Map类型对象时,我们一般可以这么创建:
1 | Map<String, List<String>> m = new HashMap<String, List<String>>(); |
但是在JDK7以上的版本,泛型参数是可以被推导出来的,所以可以有更简洁的写法:
Map<String, List<String>> m = new HashMap<>();
缺点
类如果不含有公有的或者受保护的构造方法,就不能被继承。如果使用静态工厂方法获得实例,而不提供公有的构造方法,把构造方法写为私有private,那么该类就不能被继承扩展,这就是使用复合而不是继承来扩展类了。
与其他的静态方法实际上没有任何区别。静态工厂方法其实和其他普通的静态方法是一样的,如果没有加以说明,两者不能很好被区分开来,会造成使用者不知道怎么获取该类的实例,而且不能清晰查明该类是如何被实例化的。
总结
简而言之,静态工厂方法和公有构造方法都各有用处,我们需要理解它们各自的长处。静态工厂通常更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂。