October 20, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working With Design Patterns: Singleton

  • March 20, 2008
  • By Jeff Langr
  • Send Email »
  • More Articles »

Well, a singleton is simply object-oriented speak for a global variable. The software development community has long known about problems that global variables introduce. Primarily, global variables can become a sinkhole for things that introduce tight coupling across your application.

The first thing to consider is that maybe you don't need a global variable or singleton. What would be the true harm if you created multiple instances of the potential singleton? What if you instead redesigned it to allow multiple instances? Sure, semantically there's only one master catalog in real life. But, you can design the Catalog class to encapsulate the books hash map as a static field. Your clients can create all the Catalog instances they want, but all of them point to the same static field. (This is a pattern known as monostate, by the way.)

For all the negativity about global variables and singletons, it's still a potentially legitimate construct. So, how do you know if your singleton is ill-conceived? The answer as always is testing!

You won't know whether your singleton is a problem until you try to test one of its clients. Suppose you are building a library API that interacts with the catalog, among other domain objects. Right now, such interactions probably aren't a problem, because the Catalog class is a simple hash map. But, what if the Catalog class interacted with a real database (see Listing 5)?

Listing 5: A dependency challenge.

import java.sql.*;
import java.util.*;

public class Catalog {
   private static final Catalog soleInstance = new Catalog();

   public static Catalog soleInstance() {
      return soleInstance;
   }

   private Catalog() {
      // enforce singularity
   }

   public void add(Book book) {
      try {
         Connection connection = ConnectionPool.get();
         Statement statement = connection.createStatement();
         statement.execute("insert into book // ...
            // ...
      }
   }
   //
}

Databases are always big headaches for testing. Of course, you want to verify that your Catalog class correctly interacts with Oracle and that all of your DDL is aligned with the Java code. But, you also want to verify the rest of the business logic in your application. You can do that using live interactions with the database, but such tests are very slow. They're also very painful to construct and maintain, for several reasons.

To test the rest of the classes in the system—the clients of Catalog—what you'd really like to do is to emulate the behavior of the Catalog class in what's known as a test double. At an abstract level, Catalog supports the ability to store and retrieve books associated with a specific classification. You want to mock that persistence behavior. Maybe all you really need is the map implementation above.

Unfortunately, the singleton construct says that you're stuck with the version of Catalog that mucks with JDBC. This is the chief problem with singleton: It prohibits you from creating a test double.

If you can't or won't redesign your singleton so that creating multiple instances is not harmful, there's another, better solution: Don't enforce the singleton. Right in the class file, add a comment (yes, a wonderful use of comments) to the constructor of Catalog:

public Catalog() {    // create only one, except for testing!
}

The reactions to this solution are sometimes very poor. "What if someone does create an instance?" Well, then, you have a bigger problem than the singleton. If developers won't read how to properly use a class, and heed the advice, why produce all that Javadoc that your shop no doubt requires? What's the point of code reviews, if they can't catch problems like this?

In fact, all sorts of conventions can easily be circumvented by a nefarious developer. Java even allows external access to private fields through reflection tricks! Sometimes, the best solution is to simply say, "don't do that."

You still can model the Catalog class similar to a singleton but provide hooks to allow it to cough up test doubles. You remove the private constructor from the Catalog class (see Listing 6). You provide a setInstance method to allow replacing the true, production singleton with a Catalog test double. Note the comment! You also can provide a reset method that tells the Catalog to begin using the production instance again. The reset ensures that your test doesn't gum up any other tests that expect to use the production Catalog instance.

import java.util.*;

public class Catalog {
   private static final Catalog DEFAULT = new Catalog();
   private static Catalog soleInstance = DEFAULT;

   private Map<String,Book> books = new HashMap<String,Book>();

   public static Catalog soleInstance() {
      return soleInstance;
   }

   // use for testing
   public static void setInstance(Catalog catalog) {
      soleInstance = catalog;
   }

   public static void reset() {
      soleInstance = DEFAULT;
   }
   //  ...
}

In summary, don't throw away your singletons! Just make sure that they don't cause any unit testing challenges.

About the Author

Jeff Langr is a veteran software developer with over a quarter century of professional software development experience. He's written two books, including Agile Java: Crafting Code With Test-Driven Development (Prentice Hall) in 2005. Jeff is contributing a chapter to Uncle Bob Martin's upcoming book, Clean Code. Jeff has written over 75 articles on software development, with over thirty appearing at Developer.com. You can find out more about Jeff at his site, http://langrsoft.com, or you can contact him via email at jeff at langrsoft dot com.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel