Tuesday, February 19, 2008

Singletons, Good Design or Global Disaster?

Singletons are objects that are instantiated only once throughout the life of your application. Singletons can be very useful, but like most things if they are over used they can create problems. In most cases if you can avoid using a singleton you should. With that said lets take a look at singletons and you can decide for yourself where and when to use them.

In C# a declaration of a singleton is very simple. It is simply a static object. Example:


public static MyClass MySingleton;

When you reference MySingleton you will always receive the same object from anywhere within your application. There are exceptions to this. In C# you must be in the same application domain. To ensure that other developers can't instantiate MyClass elsewhere you can make the constructor private.

Since singletons are globals and as such can be referenced anywhere in the application instantiation of the singleton is critical. I will describe 3 methods to instantiate your singleton: automatic, lazy and managed. There are strengths and weaknesses to each.

Automatic instantiation is when the singleton is created on application start. Example:

public static MyClass MySingleton = new MyClass();

This instantiation can't be used if the class constructor requires variables that are not available during application start. If you can change the MyClass constructor you can change it to not take variables, but it would not be ready to use until you set the required properties. Another option is lazy initialization.

Lazy initialization is when you instantiate your singleton on first use. Example:

public class MyClass
{
private static MyClass _mySingleton = null;

public static MyClass MySingleton
{
get
{
if (_mySingleton == null)
_mySingleton = new MyClass();

return _mySingleton;
}
}
}

In this example you would call MyClass.MySingleton to get the instance of MyClass. This is the method I prefer, but it can get messy if you have dependences. If you need more control of the initialization process you should use managed initialization.

Managed initialization gives you total control of initialization of a singleton. You get to/have to manually initialize the singleton. This means that you need to ensure that you have fully initialized your singleton before you use it. Example:

public class MyClass
{
private static MyClass _mySingleton = null;

public static MyClass MySingleton
{
get { return _mySingleton; }
set { _mySingleton = value; }
}
}

This just exposes the MySingleton object as a property. You would need to new up a MyClass object and assign it to MySingleton. Example:


MyClass.MySingleton = new MyClass();


With managed initialization you need to ensure that you initialize the MySingleton object before you try to use it. You could help ensure the MySingleton object is initialized by including an error when trying to use the MySingleton object without first initializing it. Example:

public class MyClass
{
private static MyClass _mySingleton = null;

public static MyClass MySingleton
{
get { return _mySingleton; }
set
{
if (_mySingleton == null)
throw new Exception("MySingleton has not been initialized yet.");

_mySingleton = value;
}
}
}

This will just help identify runtime errors quicker and easier.

So as you can see you can use any class as a singleton. Singletons can be initialized in a few different ways. The main advantage to Singletons can be it's weakest and strongest benefit. Singletons, because they are just a global variable, can be called anywhere in your application. This can be very helpful for classes that need to be used in many different places. This can be a problem when it comes to testing. If your testing a method that calls anything in a singleton the singleton needs to be setup for the test as well, and thus is tested as well. This also prevents the use of mock objects in testing. If you would like to learn more about mock objects check out this paper.

Singletons are a simple design pattern that can be a great tool, just consider the risks when using them.

Save to del.icio.us Add to Technorati Add to dzone

1 comment:

Jamin Roth said...

I ran across an article that adds thread safety to the singleton pattern. Check it out.