Level: Intermediate to Object Oriented Programming
Design Patterns are a very useful programming concept that
is often forgotten about in the heat of a programming project. Design Patterns
are basically code design templates that have been perfected over the years by
many different programmers and architects. They represent repetitive design
concepts that do not differ much.
One of the most famous design pattern books is called Design
Patterns – Elements of Reusable Object Oriented Software by Erich Gamma,
Richard Helm, Ralph Johnson and John Vlissides. They are collectively known as
the Gang of Four (GOF) and the book is commonly known as the GOF book. I
highly recommend this book as you learn object oriented programming. It will
start to make you think in patterns, which is essential to software. Every
application follows some similar concepts and patterns.
Many programming tasks are standard for each software project. There are many
times when you want a single instance of an object throughout the entire
application. Enter the Singleton design pattern. This pattern limits an
object to one instance in the entire application and returns that instance when
called on.
Here is a simple working singleton class.
Listing 1
using System;
namespace Singleton
{
public class Singleton
{
private static Singleton _instance = null;
private Singleton(){}
public static Singleton Instance()
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
}
}
Let us go over the code to see what happens. First we
create a class named Singleton. It has a single member variable of type
Singleton named _instance that is initialized to null. This is the one
instance of the class that all of our programs will use. We make the
constructor of the class private so that programs cannot create instances of
the class directly.
The one function created for the class is named Instance and returns an object
of type Singleton. In the function we simply check to see if the internal
variable is null, and if so create a new one. This instance is then returned.
To verify our code the following can be run.
Listing 2
Singleton S1;
Singleton S2;
S1 = Singleton.Instance();
S2 = Singleton.Instance();
MessageBox.Show(S1.Equals(S2).ToString());
This will show true in the message.
The above code is fine for single threaded applications. Now we will examine a
thread safe version of the singleton.
Listing 3
using System;
using System.Threading;
namespace Singleton
{
public class MultiSingleton
{
private static volatile MultiSingleton_instance = null;
private MultiSingleton(){}
public static MultiSingleton Instance()
{
if (_instance == null)
{
lock(typeof(MultiSingleton))
{
if (_instance == null)
{
_instance = new MultiSingleton();
}
}
}
return _instance;
}
}
}
This version of the singleton patterns is safe for
multithreaded applications. Let us examine the code to see what has changed. There
are only two significant changes: the definition of the instance variable and
the lock work in the function.
The definition of the _instance variable has added the volatile keyword. This
is to ensure that the compiler does not do any memory optimizations on our
variable by reordering our code in the function. Without the volatile keyword
the compiler might decide to remove the double check in the function.
The function can seem confusing at first, but makes sense after looking at it. A
double check is used to see if the instance variable is null. We do this
because no two threads would ever pass both conditions at the same time. If
the inner check was left out, two threads could run the null check at the same
time. Both would pass so both threads would then obtain the lock and create a
new instance of the singleton. The inner check prevents the second thread from
creating the instance, since it would not be null after the first. This brings
up the point: Why not we just write it like the following then?
Listing 4
public static MultiSingleton Instance()
{
lock(typeof(MultiSingleton))
{
if (_instance == null)
{
_instance = new MultiSingleton();
}
}
return _instance;
}
This code would work fine and be perfectly thread-safe. We
do not use the above because the lock is always entered. This is not as fast
as the previous double check code where the lock is avoided when the instance
is not null.
The singleton is a very common design pattern. I have kept the code shown as
close as possible to the GOF book’s implementation of the pattern. There are
other ways to write a singleton in .NET, but the GOF implementation is one of
the most common throughout other languages. If you understand patterns and
remember their names, it gives you the ability to converse with many other
programmers on the same level. If an architect calls for a singleton, that is
what will be asked for. The architect will not ask for a single instance of
this class throughout the application.