Click here to Skip to main content
12,507,674 members (54,420 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

8.9K views
10 bookmarked
Posted

The Hunt for Singletons

, 29 Aug 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
This article explains how Singletons can be replaced with dependency injection. It covers the advantages and how to refactor existing code.

Introduction

Since I learned about dependency injection, I always try to get rid of any Singleton pattern implementation I have in my projects. I admit, I had something other developers call ‘singletonitis’ – I used Singletons excessively. The reason that I liked Singletons so much was that when I switched my main programming language from C++ to C#, I immediately faced a problem of global variables. C# is a fully object oriented programming language, meaning there is no such thing as global variables, that we have in C++. That scared me at first, but then I found out about a way to overcome this – the Singleton pattern.

The problem Singletons solve is having a single instance of whatever type you implement it on. Whenever I needed a variable with global state, one that is shared among many other objects, I created a Singleton, like this:

public class MyClass
{
  private static MyClass instance = new MyClass();
 
  public static MyClass Instance
  {
    get { return instance; }
  }
 
  // the constructor must be private, so that no one else can instantiate this class
  private MyClass()
  {
  }
}

It’s funny though, that even when I realized that global variables are dangerous, I still didn’t associate global variable with Singleton.

The problems begin when you need to change your code to having many instances, instead of one. For example, when you write a unit test, you might want to replace your class instance with a fake object, to isolate the class under test from anything that you’re not interested in. Sure, you might open up your singleton implementation to allow you to set the instance to anything other than the default instance, like this:

...
public static MyClass Instance
{
    get { return instance; }
    set { instance = value; }
}
...

You’ve just solved the problem with faking the object, but also allowed any other code to replace the default instance. You’re not sure anymore, that you will have a single, same, instance only!

So what can be done about it? Well, since Singleton is used to ensure only one instance of a certain class exists, then just create only one class per application! A good place to create it is the bootstrapper of your program, like the Main() method in C#. That instance would then be passed to any objects that might need it through their constructors or properties. That is dependency injection. Another way is to use a Inversion of Control container, like Unity or Castle Windsor, to limit the lifetime of an object of certain class. Just configure it to be a singleton and the same instance will be passed to every object that needs it.

The benefits of this change are huge. First of all, it makes the dependencies visible to the outside world. If you use a Singleton pattern instance somewhere in your class – no one can tell that without looking at the code of that class. By passing it through a class’ constructor, you say “Hey! I need that class, else I can’t work!”. That makes your API more clear to those who see it for the first time, no magic is happening behind the scenes. You can also pass a fake object easily for unit tests.

Second, you can easily switch between having a single or multiple instances. With IoC containers, it’s just a matter of configuration. With manual factories, you can create an instance of your dependency class once, and pass it to any objects that factory creates, or create a new instance of the dependency every time and pass that.

How to start the refactoring of singletons, you might be wondering? First of all, I’d extract an interface from the Singleton class. Then, you can use the so called “Poor man’s dependency injection” technique, if you don’t want to break your code. Let’s suppose you have the following:

public class SomeClass
{
  public void DoSomething()
  {
    ...  // some logic here
    MyClass.Instance.DoSomethingElse();
  }
}

Now extract an interface from the Singleton class, let’s call it IMyClass, and apply Poor man’s DI:

public class SomeClass
{
  private readonly IMyClass myClass;
 
  public SomeClass()
    :this(MyClass.Instance)
  {
  }
 
  // the constructor used for dependency injection
  public SomeClass(IMyClass myClass)
  {
    this.myClass = myClass;
  }
 
  public void DoSomething()
  {
    ...  // some logic here
    myClass.DoSomethingElse();
  }
}

Now we have a field, myClass, that we get through our second constructor. The first constructor is the default one, notice that it injects the Singleton instance into this class. This way, we make our class ready for dependency injection but don’t break the code until you decide to completely get rid of the Singleton and use pure dependency injection. When the time comes, you just remove the default constructor and make sure all the places where SomeClass is instantiated passes an instance of IMyClass interface implementation. All the steps you do don’t break your code!

Oh, you might wonder, why do we need an interface? For decoupling. For unit tests also. You can pass any implementation of IMyClass interface to SomeClass objects. That makes it quite easy to test and extend and follows the Open/Closed Principle.

I hope I made it clear how single instance + DI is better than Singleton pattern in this article. If yes, try the refactoring I demonstrated and get rid of it!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gediminas Geigalas
Software Developer (Senior)
Lithuania Lithuania
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
GeneralMy vote of 1 Pin
filoteanuadrian2-Feb-12 23:34
memberfiloteanuadrian2-Feb-12 23:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160927.1 | Last Updated 29 Aug 2010
Article Copyright 2010 by Gediminas Geigalas
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid