Why static is Bad and How to Avoid It

Everybody who worked with a project which included a StringUtil(s) class with only static methods, raise her hand! Thought so. Are those methods bad? Probably not so much, although I had a word to say about the name, after all if a class is not a utility it isn’t useful (by the definition of Wiktionary) and we hopefully haven’t much of that kind in our projects.

But static methods turn bad, when they become more complex than the typical content of a StringUtil class. The problem is your code becomes hard wired to that static method. There is no easy way to replace the reference to the static method with something else, and if you are testing your code using automated tests, this is exactly what you want to do.

If you don’t test your code using automated tests, do something about it NOW!

Converting a static method to something easily mocked is straight forward once you’ve done it once or twice. Lets start with an example:

  1. public class Utility{
  2.     public static int doSomething(){
  3.         //…
  4.     }
  5. }
  6.  
  7. public class Client{
  8.     public void foo(){
  9.         //…
  10.         Utility.doSomething();
  11.         //…
  12.     }
  13. }

The Client uses a static method in Utility and we want to get rid of that. The first step is to make the doSomething method non-static. It is really as easy as removing the static modifier. Of course now the Client needs and instance of Utility, so we just create one for now:

  1. public class Utility{
  2.     public int doSomething(){
  3.         //…
  4.     }
  5. }
  6.  
  7. public class Client{
  8.     public void foo(){
  9.         //…
  10.         new Utility().doSomething();
  11.         //…
  12.     }
  13. }

Of course this doesn’t improve the situation much. We still have a static reference to the Utility class, since the constructor is just another static method. But now we can simply inject the dependency from the outside:

  1. public class Utility{
  2.     public int doSomething(){
  3.         //…
  4.     }
  5. }
  6.  
  7. public class Client{
  8.     private final Utility utility;
  9.  
  10.     public Client(Utility aUtility){
  11.         utility = aUtility;
  12.     }
  13.  
  14.     public void foo(){
  15.         //…
  16.         utility.doSomething();
  17.         //…
  18.     }
  19. }

Now you can replace Utility by a mocked instance for tests, you can use a wrapped instance for logging or make it implement an interface and so one. Basically you are back in OO world. Of course you can use your favorite DI-Framework to inject the dependency (just make sure you do it properly), or if you don’t mind the compile time dependency you can create an alternative constructor in the Client which uses the default implementation.

Share:
  • DZone
  • Digg
  • del.icio.us
  • Reddit
  • Facebook
  • Twitter