Wednesday 1 August 2007

Refactor singleton out of your code

There are a lot of posts about that the Singleton design pattern [GoF] is not pattern but anti-pattern (eg. SINGLETON - the anti-pattern!). Some posts also proposes an alternatives for Singleton design pattern or solutions for already existing Singleton design pattern problem (eg. Patterns I Hate #1: Singleton). But I didn't found any post which describes solution for big project with bunch of singleton class usage without big effort of rewriting many places by hand.

Because I was in situation that I should refactor a big project containing bunch of Singletons, I was thinking about some automatic way how to remove them. I found a solution using several refactorings. After bellow described sequence of steps you can replace Singleton design pattern by Registry design pattern [P of EAA] which solves all crucial problems of a Singleton, like testing possibility, singleton subclassing, ....

Lets have simple singleton class which we want to refactor to access it's instance not as a singleton but using some registry.

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

public static SingletonClass getInstance() {
return INSTANCE;
}

private SingletonClass() {
super();
}

public void voidMethod(String param) {
System.out.println("Doing something in method returning void");
}

public Object objectMethod(String param) {
System.out.println("Doing something in method returning Object");
return new String("This is an String");
}
}

and also lets have very simple client class which access the singleton

public class Client {
public void clientMethod() {
SingletonClass.getInstance().voidMethod("param");
Object object = SingletonClass.getInstance().objectMethod("param");
}
}
  • At the first I create simple interface for Registry with two simple methods - getter and setter for instance of class which is currently implemented as singleton (SingletonClass in my example). There are also other variants of Registry implementation. For example you can have one generic methods getService and setService with some selector as a parameter (String ID, service class, ...). But I choosed the simplest one.

    public interface ISingletonRegistry {
    SingletonClass getSingletonClass();
    void setSingletonClass(SingletonClass singleton);
    }

  • Make SingletonClass's constructor public

  • Then implement the interface as a simplest Registry design pattern implementation - SingletonRegistry.

    public class SingletonRegistry implements ISingletonRegistry {

    private static final SingletonRegistry INSTANCE = new SingletonRegistry();

    private SingletonClass singleton;

    public static ISingletonRegistry getInstance() {
    return INSTANCE;
    }

    private SingletonRegistry() {
    //this is the reason why the constructor should be public
    singleton = new SingletonClass();
    }

    public SingletonClass getSingletonClass() {
    return singleton;
    }

    public void setSingletonClass(SingletonClass singleton) {
    this.singleton = singleton;
    }
    }

    You can see that I implemented it as singleton (of course using practise described in one of my previous posts - Singleton pattern implementation in 4 steps :-). I know that a lot of readers will have animadversions that I am creating new singleton when I want to remove other singletons. But realize that singleton is not evil every time. Also Service Locator design pattern uses singleton to access ServiceLocator instance.
    You can also see that constructor of the class initializes reference to SingletonClass instance. Of course this is just possibility. You can use some mechanism of configuration of the singleton instances. But note that it should be performed before you use SingletonRegistry by some client for the first time by. Anyway this implicit setup can stay here because you are able to set different instance of SingletonClass using setSingletonClass method.

  • Change getInstance method of SingletonClass to get instance from SingletonRegistry.

    public static SingletonClass getInstance() {
    return SingletonRegistry.getInstance().getSingletonClass();
    }

  • Over getInstance method of SingletonClass perform Inline... refactoring (Alt+Shift+I), mark 'Delete method declaration' chekbox and click OK. The method getInstance from SingletonClass disappears and all it's client classes uses SingletonRegistry to access SingletonClass.

    public class Client {
    public void clientMethod() {
    SingletonRegistry.getInstance() .getSingletonClass().voidMethod("param");
    Object object = SingletonRegistry.getInstance() .getSingletonClass().objectMethod("param");
    }
    }

  • Delete INSTANCE constant from SingletonClass class.

  • As a cherry on top of a cake you can Extract Interface (Alt+Shift+T, E) from SingletonClass. Write just new interface name, select all methods from SingletonClass which you can extract into new interface and press OK. All references to SingletonClass will be refactored to references to your newly created interface.
And that is all. Now you have SingletonClass with totally same functionality but you are able to mock it, extend or replace by different implementation setting up your instance of SingletonClass to SingletonRegistry.

References: