More Effective .NET via Effective Java: Static Factories
December 14, 2010 | Jason Kozemczak
Yesterday, I talked briefly about one of my favorite takeaways from Joshua Bloch’s Effective Java: the typesafe enum pattern. Today I’d like to discuss another one of 57 points Bloch discusses in his book and how it can be understood and implemented from a .NET standpoint; the first point he makes in the book is to consider implementing static factory methods in your classes.
When developers start coding a class, we often start with what seems quite innocent:
Now, this is inherently bad, but we lose a certain amount of control over the use of our class when we allow public constructors. For one, we no longer have control over how many instances of a class we will allow. This might be important in a situation where we’re managing a pool of database connections, for instance.
Furthermore, if we have enough constructors, we might run into a signature collision, where the only alternative is to rearrange the parameter types of one or more constructors. This will almost always be a compromise, and probably one that comes with the cost of confusing the consumer of the class. In short, we’re limited by the fact that classes can only have 1 constructor for any given signature:
But alas, we won’t let the compiler get the best of us! We can turn our constructors into public static factory methods:
A few things to note about the above example. One, it doesn’t really make any sense; I haven’t done a good job at making a sensical class, and I apologize for that. I’ve basically hodge-podged a few static factory methods into a class to point out the advantages vs. traditional object constructors.
Static Factories Over Constructors?
By using static factory methods, we can better manage instances of our class (if we’re concerned about such things), this is highlighted in the top static method. The beauty of this implementation is that you can adjust the number of allowed instances without the user having to worry about it. You could even transform the class into a singleton by making adjustments inside the factory method!
The last two static methods are used to highlight the more descriptive nature of static factory methods vs. constructors; it also serves the purpose of showing how signature collissions become essentially a non-issue with static factory methods. Note that both static factory method’s names help to inform the user certain characteristics of the objects they return. Additionally, they share the same signature, which would not be possible if constructors had been used in their place.
Another advantage that Bloch points out that I haven’t demonstrated is that using static factory methods allows you the ability to return instances of subclasses in your static factory methods. I once wrote a small set of classes that calculated the driving distance between two locations using Google Maps and Bing Maps. I essentially subclassed the interaction between either group and created a static factory method that returned an instance of one or the other. Generally, it returned only instances of the Bing Maps-based calculator, but could have been easily “switched” out with the Google Maps-based calculator should Bing’s mapping services ever went down.
The Grass is Always Greener
To close, don’t let this post misguide you into thinking that factory methods are always superior to constructors. One of the major limitations is that without public constructors, you are essentially making your class sealed. This might potentially be bad if you explicitly want your class to be able to be subclassed. However, note that this implementation doesn’t stop users from utilizing your class through composition (in contrast to inheritance), which can sometimes be a “cleaner” way of leveraging a class’s behavior.
In addition to the “sealed” byproduct, you also fight the fact that static factory methods don’t “look” any different than other static methods in a class (i.e. they aren’t differentiated from other methods like constructors are). This could frustrate users of your classes if you aren’t descriptive in your class’s public contract. Again, use judgement and pragmatism when deciding on implemeting constructors of static factory methods (or maybe use both!).