客户端获得实例的传统方式使用类提供的构造函数。但是一个类可以提供公共静态工厂方法,它只是一个返回类实例的静态方法。下面是一个来自 Boolean (boolean 的包装类)的简单示例。该方法将 boolean 基本类型转换为 Boolean 对象的引用:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}
静态工厂的优点:
静态工厂方法与构造函数相比的第一个优点,静态工厂方法有确切名称。 如果构造函数的参数本身并不能描述返回的对象,那么具有确切名称的静态工厂则更容易使用,生成的客户端代码也更容易阅读。
静态工厂方法与构造函数相比的第二个优点,静态工厂方法不需要在每次调用时创建新对象。 这允许不可变类(Item-17)使用预先构造的实例,或在构造实例时缓存实例,并重复分配它们以避免创建不必要的重复对象。Boolean.valueOf(boolean)
方法说明了这种技术:它从不创建对象。这种技术类似于享元模式 [Gamma95]。如果经常请求相同的对象,特别是在创建对象的代价很高时,它可以极大地提高性能。
静态工厂方法与构造函数相比的第三个优点,可以通过静态工厂方法获取返回类型的任何子类的对象。 这为选择返回对象的类提供了很大的灵活性。
静态工厂的第四个优点是,返回对象的类可以随调用的不同而变化,作为输入参数的函数。 声明的返回类型的任何子类型都是允许的。返回对象的类也可以因版本而异。
静态工厂的第五个优点是,当编写包含方法的类时,返回对象的类不需要存在。 这种灵活的静态工厂方法构成了服务提供者框架的基础,比如 Java 数据库连接 API(JDBC)。服务提供者框架是一个系统,其中提供者实现一个服务,系统使客户端可以使用这些实现,从而将客户端与实现分离。
静态工厂方法的局限
仅提供静态工厂方法的主要局限是,没有公共或受保护构造函数的类不能被子类化。 例如,不可能在集合框架中子类化任何方便的实现类。
静态工厂方法的第二个缺点是程序员很难找到它们。 它们在 API 文档中不像构造函数那样引人注目,因此很难弄清楚如何实例化一个只提供静态工厂方法而没有构造函数的类。Javadoc 工具总有一天会关注到静态工厂方法。与此同时,你可以通过在类或接口文档中对静态工厂方法多加留意,以及遵守通用命名约定的方式来减少这个困扰。
静态工厂方法的常用名称
- from—A type-conversion method that takes a single parameter and returns a corresponding instance of this type, for example:
from,一种型转换方法,该方法接受单个参数并返回该类型的相应实例,例如:
Date d = Date.from(instant);
- of—An aggregation method that takes multiple parameters and returns an instance of this type that incorporates them, for example:
of,一个聚合方法,它接受多个参数并返回一个包含这些参数的实例,例如:
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
- valueOf—A more verbose alternative to from and of, for example:
valueOf,一种替代 from 和 of 但更冗长的方法,例如:
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
- instance or getInstance—Returns an instance that is described by its parameters (if any) but cannot be said to have the same value, for example:
instance 或 getInstance,返回一个实例,该实例由其参数(如果有的话)描述,但不具有相同的值,例如:
StackWalker luke = StackWalker.getInstance(options);
- create or newInstance—Like instance or getInstance, except that the method guarantees that each call returns a new instance, for example:
create 或 newInstance,与 instance 或 getInstance 类似,只是该方法保证每个调用都返回一个新实例,例如:
Object newArray = Array.newInstance(classObject, arrayLen);
- getType—Like getInstance, but used if the factory method is in a different class. Type is the type of object returned by the factory method, for example:
getType,类似于 getInstance,但如果工厂方法位于不同的类中,则使用此方法。其类型是工厂方法返回的对象类型,例如:
FileStore fs = Files.getFileStore(path);
- newType—Like newInstance, but used if the factory method is in a different class. Type is the type of object returned by the factory method, for example:
newType,与 newInstance 类似,但是如果工厂方法在不同的类中使用。类型是工厂方法返回的对象类型,例如:
BufferedReader br = Files.newBufferedReader(path);
- type—A concise alternative to getType and newType, for example:
type,一个用来替代 getType 和 newType 的比较简单的方式,例如:
List<Complaint> litany = Collections.list(legacyLitany);
总之,静态工厂方法和公共构造器都有各自的用途,理解它们相比而言的优点是值得的。通常静态工厂的方式更可取,因此应避免在没有考虑静态工厂的情况下就提供公共构造函数。