对于类而言,为了让客户端获取它自身的一个实例,最传统的方法就是提供构造方法。除此之外,我们今天将介绍的静态工厂方法也是被用得很广泛的一种方式。比如Boolean
源码中将boolean
基本类型值转换成一个Boolean
对象引用:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
如果不通过公有的构造方法,或者说除了公有的构造方法之外,类还可以给它的客户端提供静态工厂方法。提供静态工厂方法而不是公有的构造方法,这样做既有优势,也有劣势。
1. 优势
(1)第一大优势在于,静态工厂方法是有名称的。如果构造方法的参数本身没有确切地描述正在创建的对象,那么具有适当名称的静态工厂会更容易使用,产生的客户端代码也更易于阅读。
(2)第二大优势在于,不必在每次调用它们的时候都创建一个新的对象。这使得不可变类可以使用预先创建好的对象,或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象。上诉Boolean.valueOf(boolean b)
方法就是如此,它从来不创建对象,而是返回缓存中的对象。
(3)第三大优势在于,它们可以返回原返回类型的任何子类对象。比如Arrays.asList()
方法返回的就是List
接口的一个子类对象。
2. 劣势
(1)第一大劣势在于,程序员很难发现它们。在API文档中,它们没有像构造方法那样在API文档中明确标识出来,因此,对于提供了静态工厂方法而不是构造方法的类来说,要想查明如何实例化一个对象是非常困难的。这一点需要我们通过在类或者接口注释中关注静态工厂,并遵守标准的命名习惯来弥补这一劣势。下面是静态工厂方法的一些惯用名称:
from
:类型转换方法,它只有单个参数,返回该类型的一个对象。比如:Date date = Date.from(instant)
。of
:聚合方法,带有多个参数,返回该类型的一个对象,把它们合并起来。比如:Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING)
。valueOf
:比如:BigDecimal.valueOf(long val)
。instance
或者getInstance
:大部分见于单例类。create
或者newInstance
:和instance
、getInstance
一样,但create
或者newInstance
能够确保每次调用都返回一个新的实例对象。get<Type>
:像getInstance
一样,但是在工厂方法处于不同的类中的时候使用。比如:FileStore fs = Files.getFileStore(path)
。new<Type>
:像newInstance
一样,但是在工厂方法处于不同的类中的时候使用。比如:BufferedReader br = Files.newBufferedReader(path)
。type
:get<Type>
和newType
的简版,比如:List<Complaint> litany = Collections.list(legacyLitany)
。