The first item in the book “Effective Java” suggests using static factory methods instead of constructors. “But wouldn’t it make the class more complex than it should be?” I thought. After all, if you have a simple object with a single reason to change, a simple constructor would suffice. Well… We are talking about Java here where you can have multiple constructor definitions. On top of that, if your project is using a dependency injection framework like Guice, your constructor definitions are no longer yours to use. The composition of your objects is controlled by an Inversion of Control (IoC) container that can solve dependencies recursively using bindings. No manual dependencies allowed.

That’s why the static factory method suggestion intrigued me. I was trying to take control of my constructors back. While the IoC container handles the hard dependencies such as clients and services, I could utilize my manual dependencies through a static factory method. Neat. What happened at the end of reading the whole block of text about this item was certainly more than I could imagine. The reasons given by the author, Joshua Bloch, are quite convincing. So convincing that I could see myself using static factory methods over constructors (in certain cases) in other languages as well.

Static factory methods have names

Constructors are named the same as their classes. I think this is fine if you have a simple object to tinker with. However, if your domain object is intrinsically complex, then having multiple factory methods with proper names can be quite helpful.

public class Route {
	// constructor
	Route(Coordinate from, Coordinate to) {}

	// static factory methods
	public static Route newHighwayRoute(Coordinate from, Coordinate to) {}
	public static Route newScenicRoute(Coordinate from, Coordinate to) {}
}

Class of the returned object can vary

The example above simply calls for polymorphism. The Route class apparently encapsulates the logic of building a route from A to B. There are two main logic to create routes:

  1. A route that goes through the highway for fast journeys, and
  2. A route that goes through touristic areas for better scenery.

While preserving the Route class, we can apply Strategy pattern to have scalable route creation logic. Then, static factory methods help us return object with differing types:

public interface Route {}
public class HighwayRoute implements Route {}
public class ScenicRoute implements Route {}
public class RouteGenerator {
	// constructor
	RouteGenerator(Coordinate from, Coordinate to) {}

	// static factory methods
	public static HighwayRoute newHighwayRoute(Coordinate from, Coordinate to) {}
	public static ScenicRoute newScenicRoute(Coordinate from, Coordinate to) {}
}

Class of the returned object does not have to exist

Let’s assume that we decided to create another strategy for generating routes: Toll free. We’d like to offer the option of rather a fast journey like highways but without the need of paying.

In this case, we can easily create a new static factory method for immediate API access to the user. We don’t have to have a TollFreeRoute implementation yet.

public interface Route {}
public class HighwayRoute implements Route {}
public class ScenicRoute implements Route {}
public class RouteGenerator {
	// constructor
	RouteGenerator(Coordinate from, Coordinate to) {}

	// static factory methods
	public static HighwayRoute newHighwayRoute(Coordinate from, Coordinate to) {}
	public static ScenicRoute newScenicRoute(Coordinate from, Coordinate to) {}
	public static Route newTollFreeRoute(Coordinate from, Coordinate to) {}
}

Static factory methods can return subtypes

Well, that is obvious if you’ve followed the polymorphism example. Normally, the examples above should have been more strictly related to inheritance than polymorphism. Because if we continue working on the example above, the next logical step would be to strip Route logic completely from RouteGenerator and actually use RouteGenerator’s constructor:

public interface Route {}
public class HighwayRoute implements Route {}
public class ScenicRoute implements Route {}
public class TollFreeRoute implements Route {}
public class RouteGenerator {
	// constructor
	RouteGenerator(Coordinate from, Coordinate to) {}

	// generators
	public HighwayRoute getHighwayRoute() {}
	public ScenicRoute getScenicRoute() {}
	public TollFreeRoute getTollFreeRoute() {}
}

However, let’s reimagine our example with another interface: TravelMethod and have our Route class return itself based on the method of travel:

public interface TravelMethod {}
public class Route {
	// constructor
	Route(TravelMethod method) {}
}

There are different types of travel methods such as driving, walking, or public transportation. So for each and every different type, our Route implementation should construct a route. How do you differ the constructed objects? Well, perhaps we can power our Route class with multiple constructors?

public interface TravelMethod {}
public class Walking implements TravelMethod {}
public class Driving implements TravelMethod {}
public class PublicTransportation implements TravelMethod {}
public class Route {
	// constructors
	Route(Walking method) {}
	Route(Driving method) {}
	Route(PublicTransportation method) {}
}

For each type of travel method, we have a concrete Route object constructed. However, we can do better here if we use static factory methods.

public interface TravelMethod {}
public class Walking implements TravelMethod {}
public class Driving implements TravelMethod {}
public class PublicTransportation implements TravelMethod {}
public class Route {
	// static factory methods
	public static Route newWalkingRoute(Walking method) {}
	public static Route newDrivingRoute(Driving method) {}
	public static Route newPublicTransportationRoute(PublicTransportation method) {}
}

Here, we have named factory methods to differentiate between the travel methods. However, we can also invert the logic here and instead of returning a Route based on the travel method, we can return a differing type of Route based on the given implementation of TravelMethod interface.

public interface TravelMethod {}
public class Walking implements TravelMethod {}
public class Driving implements TravelMethod {}
public class PublicTransportation implements TravelMethod {}
public class WalkingRoute extends Route {}
public class DrivingRoute extends Route {}
public class PublicTransportationRoute extends Route {}
public abstract class Route {
	// static factory method
	public static Route newRoute(TravelMethod method) {}
}

Here, Route and TravelMethod have started communicating through abstractions. The abstract Route class accepts any TravelMethod implementation in its static factory method and returns a subtype of Route based on the encapsulated logic inside.

Static factory methods can return existing objects instead of instantiating new ones

Let’s revisit the RouteGenerator example from above with a bit of a twist:

public class RouteGenerator {
	RouteGenerator(Coordinate from, Coordinate to) {}
}

Imagine we are processing an expensive computation within the RouteGenerator class constructor. What happens when you’d like to get another RouteGenerator with the same coordinates? You have a few options:

  1. You can create a new instance by going through the constructor. This will be another expensive operation.
  2. You could cache the old RouteGenerator object beforehand and hit the cache next time you need it.
  3. You can have a manager class to have strict control over instances.

When you followed the third approach, you’d actually cover all those options in a best case scenario:

public class RouteManager {
	private HashMap<Coordinates, Route> routes = new HashMap<>();
	public static Route getRoute(Coordinate from, Coordinate to) {}
}

Here, our RouteManager controls the creation of Route instances. When RouteManager.newRoute(from, to) is called for the first time, the expensive operation is processed and it’s cached in the instance variable routes. Next time you call RouteManager.newRoute(from, to) with the same arguments, it’s going to be served from the routes variable instead of creating the same Route again.

This approach can be globalized with Singleton pattern where you give the instance control to its own class. However, I wanted to keep the example simple without going into Singleton because it’s a controversial pattern.

Limitations of static factory methods

According to Joshua Bloch, there are two main limitations of using static factory methods. First, they are not as easy as finding constructors in the API documentation since they are not treated as constructors. The second one is that classes without non-private constructors cannot be subclassed. This may be a good side-effect, though, as Bloch also states, because one will have to use composition over inheritance.

Some of the examples above can also be achieved in simple compositional logic. Static factory method is a shiny name to decouple construction logic away from the class itself. However, you can achieve the similar or even better results by refactoring into deeper models. So you don’t have to go apply static factory methods everywhere instead of using the core principles such as composition, polymorphism, and KISS. But I’m sold on the idea of using them where it’s not easy or simple to encapsulate the domain logic with plain objects. Heck, I’m even getting used to using Singleton objects but that’s for another post.