Wednesday, 21 May 2008

Static Utility Methods

A few of us were chatting about static methods the other day.
I'm not a big fan. I think that they tie you unnecessarily to a concrete class.

Most people were saying that there is no harm in having static methods in utility classes, and this is one place where I would disagree.
The example used was the java.lang.Math class with it's utility methods.

java.lang.Math is non-instantiable, you can only access it's utility methods through static calls.
For the most part, this is fine, but take the example of Math.sqrt(x)
This method returns NaN if x is < 0. For the majority of cases this is fine, but if I start working with complex numbers, then this is no longer the ideal behaviour.
Admittedly, in this case I would not want the return value to be a double, but I may want it to throw a ComplexNumberException or something similar. If I have used the static method throughout my code, I now have to go and update every single reference to the concrete class. What a pain in the class!

However, if I had used a utility class with instance methods, I could have injected the utility class in the constructor and I could now change it out for my new ComplexMathUtility class through configuration / DI.

This isn't the best example, as the required return types are different, but think of a String utility class, perhaps something that formats a header for a report.
We could (naively) implement this using static utility methods. If we later require two different types of report heading, this is going to make our life difficult.
If we implement this using an instantiable ReportFormatter, we can swap in new ones at runtime / configuration. We've just implemented a ReportFormatterStrategy :-)

My feeling is that implementing utilities as instance methods keeps the design flexible and allows for more code reuse as things naturally gravitate towards smaller, more easily testable, logically grouped units of functionality...
Or am I just dreaming? :-)

2 comments:

Mc said...

You'd have to involve at least 3 classes and some DI library refs to accomplish your two strategies scenario. Even then you're still coupled to one of those 3 types (interface or abstract class supertype). This complexity may be appropriate at some times, but the setup/overhead/code is overkill for a great number of common cases. Think of Math.cos or StringUtils.reverse - very unlikely that'd you'd want to change those, much less do the plumbing for keeping instances of those utility class available in some global context.

Your post did leads me to wonder: what if static methods could be "extended" how might that work. I certainly haven't thought through that extensively. I'm sure the java language people have, and there must be great reasons why its not possible.

Maybe look at it this way: using "composition," you can make whatever instantiable utility classes to wrap any existing other classes/methods you find are otherwise unsatisfactory.

Andy said...

It's true with StringUtils.reverse that I would be unlikely to want to change the implementation, but I would much rather write:
"abc1234".reverse();
than:
StringUtils.reverse("abc1234");

I think if I bumped into one of the instances I mentioned where I wanted to be able to change out the configuration at runtime, then I would use an instance wrapper around a static method...

My opinions are no way set in stone, it's just that static methods make me feel icky and I'm not 100% sure why :-)