11 February 2012

Singleton, testing and dependency inversion

Singleton: pattern or antipattern?
Accordingly to Wikipedia, Singleton is a creational pattern, used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object. So, it's a pattern!
But it's an antipattern, too, especially from the point of view of testing: it's a (simple) variant of Service Locator testability antipattern.

As states Jens Schauder in his post Fixing the Singleton, there are two key characteristic of the (classic implementation of) singleton:
  • There can be only a single instance of the class developed as singleton
  • There is a central, global acces point to the singleton instance
Alhough the first one is the main - if not the only - reason for use of Singleton pattern, it comes almost alway with the second one. But... while the first one is a conceptual featur of the pattern, the second is nothing but an implementation detail!

We can therefore speak of conceptual Singleton, when we have a class that can be instantiated only once in the application lifecycle, and syntactic Singleton, with reference to the traditional GoF's implementation. 
Well, my idea is that you can think of two different basic implementation strategies for conceptual Singletons:
  • Singleton by syntax - traditional GoF's implementation, through private static instance and public static (and then: global) accessor
  • Singleton by contract / application - implementation of the concept of "single class instance" without syntactic constraints: application code takes care of respect the contract of "single instance". Tipically, application infrastructure responsible for creating object and setting up collaborators references instantiates the Singleton class only once and passes created instance to modules interested in its use: this is substantially an application of Dependency Inversion Principle, and can be implemented through Inversion of Control frameworks like Spring and Google-Guice (for a good discussion about self implemented dependency injection, see this article).
First approach suffers the problem suggested initially: there is a global state, publicly accessible, liberally referenced everywhere in the client code - and global state is evil!
The second one, instead, provides a conceptual Singleton instance without referring to syntactical constraints: application lifecycle infrastructure ensures unicity of the Singleton class instance.

In code:
  • Singleton by syntax:
    package singleton;

    public class UIDGenerator {
      private static final UIDGenerator INSTANCE = new UIDGenerator();

      public static UIDGenerator getInstance() {
        return INSTANCE;

      }

      private UIDGenerator() {
      }

      public String nextId() {
        return ...;
      }
    }

    Client code:

    public void foo() {
      String newId = UIDGenerator.getInstance().nextId();
      // Use newId
    }
      
    public void bar() {
      Account account = new Account(UIDGenerator.getInstance().nextId());
      // Use newly created Account
    }
    This the classical GoF's implementation of pattern Singleton: private constructor and final static INSTANCE ensure instance unicity, public static accessor provides global access to singleton instance.
  • Singleton by contract:
    package singleton;

    public interface UIDProvider {
      public abstract String nextUid();
    }


    Client code:

    package singleton;

    public class AccountManager {
      private final UIDProvider uidProvider;

      public AccountManager(UIDProvider uidProvider) {
        this.uidProvider = uidProvider;
      }
      
      public void bar() {
        Account account = new Account(uidProvider.nextUid());
        // Use newly created Account
      }
    }
In the second implementation we define an interface for UID generation: application infrastructure (i.e.. in most cases. an Inversion of Control container, like Spring) will ensure that a single instance of a class implementing UIDProvider is passed whenever it's necessary.
This way we can obtain the conceptual part of the pattern without the syntactical one: there is no public static context accessed everywhere, and a reference to the singleton is indeed injected into modules that need it. So, unlike in the first case, it's possibile to mock UIDProvider for testing purposes (for example because real implementation is time expensive, or there is a fee for every use, or simply because unit testing is isolation testing and we need to make assumptions on generated uid in testing code):

public class AccountManagerTest {
  @Test
  public void testMethod() {
    AccountManager underTest = new AccountManager(new FixedUIDProvider());
    // Exercises underTest
  }
}


This is IMHO a more, more (more!) powerful approach for implementing singleton than the classic one: can you figure out how to mock UIDGenerator.getInstance().nextId() calls?
The basic idea behind this proposal is a variation of single responsibility principle: classic singleton implementation drives to classes that implement two responsibilities: a functional responsibility - what the class do - and a structural responibility - how is the class instantiated and the instance accessed. Inversion of Control containers, and more generally the idea of Dependency Inversion, support separation of responsibilities by divide functional code and object graph lifecycle management code: this leads to clearer, simpler design, that decouples singleton implementations from client modules and supports testing in a more effective way.

1 comment:

  1. Nice post. Singleton remains a powerful core java pattern and has its place in between Static utility class. as you said classical example is JDK itself which provides both java.lang.Math and java.lang.Runtime differently. Though Singleton seems easy many programmer mess it up when asked write code for Singleton. I have shared few questions as 10 interview question on Singleton pattern in java let me know how do you find it.

    ReplyDelete