Disclaimer: This article is only for personal learning and communication, do not be used for commercial purposes, if this article is used for commercial purposes, the consequences are at your own risk, and I have nothing to do with it.

The traditional way a class allows clients to get instances is by providing a common constructor. There is another technique that should be part of every programmer’s toolbox. A class can provide a public static factory method, which is simply a static method that returns an instance of the class. Here is a simple example of a Boolean (boxed primitive class of Boolean types). This method converts a Boolean primitive value to a Boolean object reference:

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}
Copy the code

Note: The static factory method is different from the factory method pattern of design pattern [Gamma95]. The static factory method described in this Item is not equivalent to the factory method pattern of design pattern.

A class can provide its clients with static factory methods instead of public constructors. Providing static factory methods instead of public constructors has both advantages and disadvantages.

One advantage of static factory methods is that they have names, whereas constructors have the same names. If the constructor parameters themselves do not describe the object returned, it is easier to use a nicely named static factory, and the generated client code is easier to read. For example, a constructor for BigInteger: BigInteger(int, int, Random). This constructor returns a BigInteger, possibly a prime number. It is easier to describe the type of BigInteger returned by a well-named static factory method. Such as BigINTEger.probablePrime (which was added in Java 4).

A class can have only one constructor with a given signature. Programmers can get around this limitation by providing two constructors whose argument lists differ only in the order of the argument types. This is a pretty bad idea. This way users of the API will never remember which constructor to use and will end up calling the wrong one. People who use these constructors have no idea what the code does without reading the reference class documentation.

Because static factory methods have names, there is no such limitation, and in cases where a class requires multiple signatures, multiple constructors, substituting static factory methods for constructors, and choosing method names carefully, can highlight the differences between constructors.

The second advantage of static factory methods is that, unlike constructors, they do not need to create a new object each time they are called. This allows immutable classes (item 17) to use pre-constructed instances, or to cache instances at build time and distribute them repeatedly to avoid creating unnecessary duplicate objects. The Boolean. ValueOf (Boolean) method uses this approach: it never creates an object. This technique is similar to the Meta model [Gamma95]. It can greatly improve performance if equivalent objects are requested frequently, especially if they are expensive to create.

The ability of static factory methods to return the same object from repeated calls allows classes to maintain tight control over instances at all times. Classes that do this are considered instance controlled. There are several reasons to write instance control classes. Instance control allows a class to guarantee that it is a singleton (item 3) or non-instantiated (item 4), and it allows an unvalued class (item 17) to guarantee that no two equal instances exist: A.equals (b) returns true if and only if a==b is true. This is the basis of the Primitive schema [Gamma95], and enumeration types provide this guarantee.

A third advantage of static factory methods is that, unlike constructors, their objects can be instance objects of any subclass of the return type. This gives you great flexibility in choosing the class of the object to return.

One application of this flexibility is that the API can return objects without making the object’s classes programmatically public, and hiding the implementation classes in this way makes the API very concise. This technique works well in interface-based frameworks (see item 20), where the interface provides a natural return type for static factory methods.

Prior to Java 8, interfaces could not have static methods. By convention, static factory methods for interfaces named Type are placed in a non-instantiable companion class called Types (Item 4). For example, the Java Collections Framework has 45 convenient implementations that provide immutable Collections, synchronous Collections, and so on. Almost all of these implementations are exported in a non-instantiable class (java.util.Collections) via static factory methods. All classes that return objects are non-public.

The Collections Framework API is now much smaller than the 45 separate public classes exported, one for each convenient implementation. This reduces not only the number of apis, but also the conceptual weight: the number and difficulty of concepts the programmer must master in order to use the API. The programmer knows that the returned object has exactly the API specified by its interface, so there is no need to read additional class documentation for the implementation class. In addition, this factory approach requires the client to refer to the returned object through the interface rather than the implementation class, which is usually a good practice (item 64).

Since Java 8, the restriction that interfaces cannot contain static methods has been removed, so there is generally no reason to provide an interface with an accompanying class that cannot be instantiated. Many public static members should be placed in the interface itself. Note, however, that it may still be necessary to put a lot of the implementation code in separate package-private classes behind these static methods. This is because Java 8 requires that all static members of an interface be public. Java 9 allows private static methods, but static fields and static member class attributes are still required to be public.

A fourth advantage of the static factory method is that the class of the object returned by the static factory method can change with each call, depending on the parameter values of the static factory method. This is allowed as long as the type returned is a subclass of the declared class. The classes that return objects may also vary from release to release.

There are non-public constructors in the EnumSet class (item 36), only static factory methods. In the OpenJDK implementation, they return an instance of one of two subclasses, depending on the size of the underlying enumeration type: if it has 64 or fewer elements, as most enumeration types do, the static factory returns a RegularEnumSet instance, which is supported by a single long; If the enumeration type has 65 or more elements, the factory returns a JumboEnumSet instance supported by a long array.

The existence of these two implementation classes is not visible to the client. If RegularEnumSet no longer provides performance benefits for small enumerated types it can be removed from future releases without any ill effects. Similarly, a third or fourth implementation of EnumSet could be added in the future if it proves beneficial for performance. Customers neither know nor care about the type of object they get from the factory; they only care that it is some subclass of EnumSet.

A fifth advantage of the static factory method is that the returned object belongs to a class that does not have to exist when writing the class containing the static factory method. This flexible static factory approach forms the basis of the Service Provider Framework, such as the JDBC(Java Database Connectivity)API. A service provider framework is a system by which providers implement services, and the system makes the implementation available to clients, separating the client from the implementation [microservices].

There are three basic components in the service provider framework: Service interface provider, which represents an implementation; provider registry API, which is used by the provider to register the implementation; and service access API, which the client uses to obtain instances of the service. Without such a standard, apis return instances of default implementations or allow clients to loop through all available implementations. Service access apis are flexible static factories that form the basis of the service provider framework.

An optional fourth component of the service provider framework is the service provider interface, which describes the factory object that generates the service interface instance. In the absence of a service provider interface, the implementation must be instantiated repeatedly (item 65). For the JDBC Connection as part of the service interface, DriverManager. RegisterDriver is registered provider API, DriverManager. GetConnection is service access API, A Driver is a service provider interface.

There are many variations of the service provider framework pattern. For example, a service access API can return a richer service interface to a client than the one provided by the provider. This is bridge mode [Gamma95]. Dependency injection frameworks (Item 5) can be considered powerful service providers. Starting with Java 6, the platform includes a generic service provider framework java.util.Serviceloader, so you don’t need (and usually shouldn’t) write it yourself (item 59). JDBC does not use ServiceLoader because the former precedes the latter.

The main limitation of the static factory approach is that a class cannot be subclassed if it does not contain a public or protected constructor. For example, it is not possible to subclass any convenient implementation classes in the Collections Framework. But this may be a blessing in disguise, as it encourages programmers to use composition rather than inheritance (item 18) and requires immutability (item 17).

The second disadvantage of static factory methods is that they are hard for programmers to find. They don’t stand out in the API documentation as constructors do, so it’s hard to figure out how to instantiate a class that provides static factory methods instead of constructors. The Javadoc tool may one day draw attention to the static factory approach. In the meantime, you can reduce this problem by drawing attention to static factories in class or interface documents and following common naming conventions. Here are some common names for static factory methods. The list is far from exhaustive:

  • From: A type conversion method that takes a single parameter and returns the corresponding instance of the type, for example:Date d = Date.from(instant);
  • Of: an aggregation method that takes multiple arguments and returns an instance of the type containing them, for example:Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • ValueOf: A more detailed alternative, for example:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • Instance or getInstance: Returns the instance described by its arguments (if any), but cannot be said to have the same value, for example:StackWalker luke = StackWalker.getInstance(options);
  • Create or newInstance: similar to instance or getInstance, except that it guarantees that each call returns a newInstance, for example:Object newArray = Array.newInstance(classObject, arrayLen);
  • GetType: Similar to getInstance, it is used when the factory method is in a different class. Type refers to the Type of the object returned by the factory method, for example:FileStore fs = Files.getFileStore(path);
  • NewType: Similar to newInstance, this is used when factory methods are in different classes. Type refers to the object Type of the factory method orientation, for example:BufferedReader br = Files.newBufferedReader(path);
  • Type: A succinct alternative to getting type and new type, such as:List<Complaint> litany = Collections.list(legacyLitany);

In summary, both static factory methods and public constructors have their uses, and it’s worth understanding their relative advantages. Static factories are usually preferred. Instead of using constructors first, consider using static factory methods first.