Static factory methods vs traditional constructors

I’ve previously talked a little bit about the Builder Pattern, a useful pattern to instantiate classes with several (possibly optional) attributes that results in easier to read, write and maintain client code, among other benefits. Today, I’m going to continue exploring object creation techniques but this time for a more general case.

Take the following example, which is by no means a useful class other than to make my point. We have a RandomIntGenerator class that, as the name suggests, generates random int numbers. Something like:

public class RandomIntGenerator {
    private final int min;
    private final int max;

    public int next() {...}
}

Our generator takes a minimum and maximum and then generates random numbers between those 2 values. Notice that the two attributes are declared final so we have to initialize them either on their declaration or in the class constructor. Let’s go with the constructor:

    public RandomIntGenerator(int min, int max) {
        this.min = min;
        this.max = max;
    }

Now, we also want to give our clients the possibility to specify just a minimum value and then generate random values between that minimum and the max possible value for ints. So we add a second constructor:

    public RandomIntGenerator(int min) {
        this.min = min;
        this.max = Integer.MAX_VALUE;
    }

So far so good, right? But in the same way that we provided a constructor to just specify the minimum value, we want to do the same for just the maximum. We’ll just add a third constructor like:

    public RandomIntGenerator(int max) {
        this.min = Integer.MIN_VALUE;
        this.max = max;
    }

If you try that, you’ll get a compilation error that goes: Duplicate method RandomIntGenerator(int) in type RandomIntGenerator. What’s wrong?

The problem is that constructors, by definition, have no names. As such, a class can only have one constructor with a given signature in the same way that you can’t have two methods with the same signature (same return type, name and parameters type). That is why when we tried to add the RandomIntGenerator(int max) constructor we got that compilation error, because we already had the RandomIntGenerator(int min) one.

Is there something we can do in cases like this one? Not with constructors but fortunately there’s something else we can use: static factory methods, which are simply public static methods that return an instance of the class. You’ve probably used this technique without even realizing it. Have you ever used Boolean.valueOf? It looks something like:

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

Applying static factories to our RandomIntGenerator example, we could get:

public class RandomIntGenerator {
    private final int min;
    private final int max;

    private RandomIntGenerator(int min, int max) {
        this.min = min;
        this.max = max;
    }
    
    public static RandomIntGenerator between(int max, int min) {
        return new RandomIntGenerator(min, max);
    }
    
    public static RandomIntGenerator biggerThan(int min) {
        return new RandomIntGenerator(min, Integer.MAX_VALUE);
    }
    
    public static RandomIntGenerator smallerThan(int max) {
        return new RandomIntGenerator(Integer.MIN_VALUE, max);
    }

    public int next() {...}
}

Note how the constructor was made private to ensure that the class is only instantiated through its public static factory methods. Also note how your intent is clearly expressed when you have a client with RandomIntGenerator.between(10,20) instead of new RandomIntGenerator(10,20)

It’s worth mentioning that this technique is not the same as the Factory method Design Pattern from the Gang of Four. Any class can provide static factory methods instead of, or in addition to, constructors. So what are the advantages and disadvantages of this technique?

We already mentioned the first advantage of static factory methods: unlike constructors they have names. This has two direct consequences,

  1. We can provide a meaningful name for our constructors.
  2. We can provide several constructors with the same number and type of parameters, something that as we saw earlier we can’t do with class constructors.

Another advantage of static factories is that, unlike constructors, they are not required to return a new object every time they are invoked. This is extremely useful when working with immutable classes to provide constant objects for common used values and avoid creating unnecessary duplicate objects. The Boolean.valueOf code that I showed previously illustrates this point perfectly. Notice that this static method returns either TRUE or FALSE, both immutable Boolean objects.

A third advantage of static factory methods is that they can return an object of any subtype of their return type. This gives you the possibility to change the return type freely without affecting clients. Moreover, you can hide implementation classes and have an interface-based API, which is usually a really good idea. But I think this can be better seen by an example.

Remember the RandomIntGenerator at the beginning of this post? Let’s make that a little bit more complicated. Imagine that we now want to provide random generators not just for integers but for other data-types like String, Double or Long. They are all going to have a next() method that returns a random object of a particular type, so we could start with an interface like:

public interface RandomGenerator<T> {
    T next();
}

Our first implementation of the RandomIntGenerator now becomes:

class RandomIntGenerator implements RandomGenerator<Integer> {
    private final int min;
    private final int max;

    RandomIntGenerator(int min, int max) {
        this.min = min;
        this.max = max;
    }

    public Integer next() {...}
}

We could also have a String generator:

class RandomStringGenerator implements RandomGenerator<String> {
    private final String prefix;

    RandomStringGenerator(String prefix) {
        this.prefix = prefix;
    }

    public String next() {...}
}

Notice how all the classes are declared package-private (default scope) and so are their constructors. This means that no client outside of their package can create instances of these generators. So what do we do? Tip: It starts with “static” and ends with “methods”.
Consider the following class:

public final class RandomGenerators {
    // Suppresses default constructor, ensuring non-instantiability.
    private RandomGenerators() {}
    
    public static final RandomGenerator<Integer> getIntGenerator() {
        return new RandomIntGenerator(Integer.MIN_VALUE, Integer.MAX_VALUE);
    }
    
    public static final RandomGenerator<String> getStringGenerator() {
        return new RandomStringGenerator("");
    }
}

RandomGenerators is just a noninstantiable utility class with nothing else than static factory methods. Being on the same package as the different generators this class can effectively access and instantiate those classes. But here comes the interesting part. Note that the methods only return the RandomGenerator interface, and that’s all the clients need really. If they get a RandomGenerator<Integer> they know that they can call next() and get a random integer.
Imagine that next month we code a super efficient new integer generator. Provided that this new class implements RandomGenerator<Integer> we can change the return type of the static factory method and all clients are now magically using the new implementation without them even noticing the change.

Classes like RandomGenerators are quite common both on the JDK and on third party libraries. You can see examples in Collections (in java.util), Lists, Sets or Maps in Guava. The naming convention is usually the same: if you have an interface named Type you put your static factory methods in a noninstantiable class named Types.

A final advantage of static factories is that they make instantiating parameterized classes a lot less verbose. Have you ever had to write code like this?

Map<String, List<String>> map = new HashMap<String, List<String>>();

You are repeating the same parameters twice on the same line of code. Wouldn’t it be nice if the right side of the assign could be inferred from the left side? Well, with static factories it can. The following code is taken from Guava’s Maps class:

  public static <K, V> HashMap<K, V> newHashMap() {
    return new HashMap<K, V>();
  }

So now our client code becomes:

Map<String, List<String>> map = Maps.newHashMap();

Pretty nice, isn’t it? This capability is known as Type inference. It’s worth mentioning that Java 7 introduced type inference through the use of the diamond operator. So if you’re using Java 7 you can write the previous example as:

Map<String, List<String>> map = new HashMap<>();

The main disadvantage of static factories is that classes without public or protected constructors cannot be extended. But this might be actually a good thing in some cases because it encourages developers to favor composition over inheritance.

To summarize, static factory methods provide a lot of benefits and just one drawback that might actually not be a problem when you think about it. Therefore, resist the urge to automatically provide public constructors and evaluate if static factories are a better fit for your class.

About these ads

14 thoughts on “Static factory methods vs traditional constructors

  1. Only thing which I found goes a tough against static factory method is readability. Since many Java programmer are so used of new() keyword for creating object, they take some time to find out where an object is get created. Though this is not a big issue and like any other practice it will take some time to get adapted. Advantages offered by Factory design pattern is immense.

  2. 1 Map<String, List> map = new HashMap<String, List>();

    You are repeating the same parameters twice on the same line of code. Wouldn’t it be nice if the right side of the assign could be inferred from the left side?

    Since Java SE 7 use diamond inference: Map<String, List> = new HashMap;

  3. The problem with static methods is, that they can not be part of an interface. Java knows only object interfaces but not class interfaces. Object interfaces are interfaces which specify operations that can be done with objects. Class interfaces are interfaces which specify operations that can be done with classes. The creation of an object is a class operation. In Java it is done be specifying only the class name (new Object). If you implement the object creation in a static method, you can not write an interface for those methods. And so it is not possible to write an interface for the object creation itself but only for the object usage. This becomes a problem if you start with meta-object programming. A typical example of meta-object programming is a generic DAO implementation, which operates on database entities and tries to present the database entities as Java objects. In this case the DAO classes are working on DB entity classes. There is no way to solve this problem with static factory methods. And this means it is quite dangerous to implement object creations with static methods, because it prevents meta-object programming in Java.

  4. Good article but having doubt – when u say-“Another advantage of static factories is that, unlike constructors, they are not required to return a new object every time they are invoked.” Static factory method must have a call to constructor with new operator it means creation of fresh object.how are we using than existing object. Pl clarify .??

    • What I mean by that is that your factory method must NOT necessarily need to do a “new X()” every time it is invoked.
      An easy way to see this is with the Boolean.valueOf example that is on the article. Because there are only 2 possible values for a Boolean object, the class creates this 2 values as constants. Then, when someone calls the factory method “valueOf(boolean b)”, this method can just return one of the two already created constants instead of creating a new Boolean object every time.

      Does that help?

  5. Nice post :) I was wondering, when would you use a class of static factory methods as opposed to a builder object, as they both provide similar advantages?

    • I usually use a builder object when my class has a big number of attributes that need to be initialized with some of them being required and some of them being optional. Having a builder allows you to clearly express this intent using a fluent interface. If you have a small number of attributes or if all of them are required then a builder doesn’t really help much.

      Static factories, on the other hand, are pretty useful when you want to have several constructors that take the same number and type of parameters (like the Random generator example on this post) or when you want to give a more meaningful name to your constructors, regardless of the number of attributes that you actually have in your class.

      Hope that helps.

  6. The main disadvantage of static factories is that classes without public or protected constructors cannot be extended.

    I am not clear about the above point .. Could u please give me an example ….

    • Notice that the constructor in the static factory class is made explicitly private to disable instances of that class to be created. This is because you are only interested on the static methods so it would not make any sense to have instances of this class.

      Now, in Java, a class without a public or protected constructor (meaning a class with only one or more private constructors) can not be extended by other class simply because you could not create instances of that class.
      If you try to do this in Java you will get a compile error saying: “Implicit super constructor PrivateConstructorClass() is not visible for default constructor. Must define an explicit constructor”

  7. Great Work, i started reading about this topic in Effective Java. I was not able to understand properly and just browsed for the topic..found your article and understood thoroughly. Thanks for taking time and writing such articles :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s