When it comes to object creation, a class can provide static factory methods in addition to (or instead of) public constructors. This post presents a comparison of static factory methods and public constructors based on the second edition of Effective Java.
Unlike constructors, static factory methods have names. An example of this advantage is BigInteger.probablePrime, a method whose name describes the contents of the object it returns. Static factory methods may return already existing objects. This allows a class to avoid creating identical immutable objects. Therefore, it can greatly improve performance if equivalent objects are requested often. Classes that keep track of already created instances are said to be instance-controlled. Immutable instance-controlled classes can make the guarantee that no two equal instances exist (this is, if a.equals(b), then a == b). This allows client code to use the == operator, which may improve performance slightly. Enumerated types provide this guarantee.
Static factory methods can return an object of any subtype of their return
type. This allows for an API to return objects without making their classes
public. This is common in interface-based frameworks, where the return types of
the static factory methods are interfaces. As Interfaces cannot have static
methods, by convention, static factory methods for an interface named Type
are put in an non-instantiable class called Types
(remember using Executors
to get an Executor
?). The Java Collections framework, for instance, has many
nonpublic classes that implement its different Interfaces.
Static factory methods may also reduce the verbosity of creating parameterized type instances. If there is a static factory method such as
public static <T> Bucket<T> newInstance() {
return new Bucket<T>();
}
then it is possible to use
Bucket<Water> myBucket = Bucket.newInstance();
making the code shorter and clearer (the ability of the compiler to figure out the type T is known as type inference). The improvement is more noticeable for big and complicated parameterized types. Of course, if you can use Java 7 (or a newer version), the diamond operator allows you to omit the redundant parameters.
Providing only static factory methods makes it impossible to subclass classes without public or protected constructors. This, however, also encourages programmers to use composition over inheritance, which is good.
Static factory methods are not readily distinguishable from other static
methods. Sometimes it may be hard to figure out how to instantiate a class
that provides static factory methods instead of public or protected
constructors. To solve this problem, it is a good idea to use common names for
static factories, such as getInstance
, newInstance
, getType
, and
newType
.
Static factory methods and public constructors both have their uses and merits. Often static factories are better, so avoid the urge to provide public constructors without even considering static factories.