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:
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:
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:
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:
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:
Applying static factories to our
RandomIntGenerator example, we could get:
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
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,
We can provide a meaningful name for our constructors.
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
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
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.
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:
Our first implementation of the
RandomIntGenerator now becomes:
We could also have a String generator:
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:
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
RandomGenerators are quite common both on the JDK and on third
party libraries. You can see examples in
Collections (in java.util),
Maps in Guava. The
naming convention is usually the same: if you have an interface named
put your static factory methods in a noninstantiable class named
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?
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
So now our client code becomes:
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:
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.