Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

How to make Singletons whose behaviour can be overridden with a Mock object

3.00/5 (1 vote)
1 Mar 2010GPL31 min read 1   75  
How to make Singletons whose behaviour can be overridden and that allows mock objects.

Introduction

How can we create a class which has the advantages of a Singleton and still supports mock objects and changing behavior?

Background

The Singleton Design Pattern provides developers with a feature where you can guarantee a single instance throughout the life of the application. But, this behavior does not come free and without any problems. The biggest problem is that a Singleton class' behavior cannot be changed in future. Further Mock objects cannot be created, and hence Unit Testing is almost impossible because of bound dependency.

Using the code

Consider the code:

Java
class Singleton 
{  
    private Singleton static instance;
    protected Singleton()
    {
    }
    public static Singleton getInstance()
    { 
        if(instance == null) 
            instance = new Singleton();
        return instance; 
    }

    public void show()
    { 
        System.out.println("Bye..."); 
    }
}

Although this class guarantees single instance, it does not allow changing the behavior of its methods like show(). This may not be apparent, but since the instance returned is always of a Singleton class, the behavior is not changeable!

Going forward, we can do some dependency injection. Now, consider the class MySingleton:

C#
class MySingleton
{    
    private static MySingleton instance;
        
    /**
     * Singleton creator
     */
    private static MySingletonCreator creator;
    
    public static void setCreator(MySingletonCreator creator) 
    {
        MySingleton.creator = creator;
    }    
    
    /**
     * Only subclass can use
     */
    protected MySingleton()
    {        
    }
    
    // This is the behavior which developer wants to change !
    public void show()
    {
        System.out.println("Hello...");
    }
    
    public static MySingleton getInstance()
    {
        if(instance == null)
        {
            if(creator == null)
                instance = new MySingleton();
            else 
                instance = creator.create();
        }
        return instance;
    }
    
    public static interface MySingletonCreator
    {
        public MySingleton create();
    }
}

As you can see, the creation of an instance is done by the creator.create() method call.

The creator can be set right before any instance is demanded, thus allowing the developer to install a creator, its own creator which returns a specialized or mock Singleton !

Now, here is an example:

C#
public class SingletonDemo {

    public static void main(String[] args) 
    {
        // Set the creator
        MySingleton.setCreator(new MySingletonCreatorImpl());
        MySingleton ms = MySingleton.getInstance();
        ms.show();
    }

    static class MySingletonCreatorImpl implements MySingletonCreator
    {
        @Override
        public MySingleton create() 
        {
            return new MockSingleton();
        }
        
        class MockSingleton extends MySingleton
        {
            @Override
            public void show() 
            {
                System.out.println("Bye...");
            }
        }
        
    }
}

Here, as we can see, we are setting the creator which is our specialized creator which further returns a mock Singleton. This MockSingleton has the behavior we want.

Unit Testing this Singleton class is very easy as we just need to install our creator by calling setCreator() before an instance is created. We can have our own MockSingleton with any overridden method.

Points of Interest

Singletons are a boon, but they make life miserable when it comes to a unit test or mock. This way, we can get some control over the Singletons.

History

n/a

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)