The Design
The following fragment of a UML static diagram shows the design of Singleton class.
Points of note:
- Generic class with parameter T
- Instance is referenced by the static generic member singletonInstance
- The static method GetInstance returns the singleton instance or constructs an instance if one has not already been instantiated (lazy instantiation)
- The static Reinitialize method simply sets the singleton reference to null and invokes GerInstance (causing the state to be reset which could be important for some types of singletons)
- The methods GetInstance and Reinitialize use the lock statement to ensure thread-safety
/// <summary>
/// Provides an implementation of the Singleton design pattern. This can be used
/// for resource type objects such as exception handlers.
/// </summary>
/// <typeparam name="T">The type that inherits and hence implements the Singleton design pattern</typeparam>
public abstract class Singleton<T> where T:class
{
#region STATIC DATA MEMBERS
/// <summary>
/// The single instance of the subclass
/// </summary>
private static T singletonInstance;
/// <summary>
/// Object instance is used for concurrency control
/// </summary>
private static readonly object lockingObject = new object();
#endregion
#region STATIC METHODS
/// <summary>
/// Returns the instance of the class that derives from this class or creates an
/// instance if one does not already exist.
/// </summary>
/// <returns>The instance of the class derived from Singleton</returns>
public static T GetInstance()
{
lock (lockingObject)
{
if (SingletonInstance == null)
{
// Use reflection to instantiate a new instance of the class T. This
// is required as instantiating a new instance directly (new T) would
// violate the basic principle of why the sinleton pattern is used as there
// would have to be a public constructor
SingletonInstance = UtilityHelper.ConstructParameterlessInstanceOfType<T>(BindingFlags.Instance | BindingFlags.NonPublic);
}
}
return SingletonInstance;
}
/// <summary>
/// Gets the single instance of the sub-class that derives from this Singleton
/// </summary>
protected static T SingletonInstance
{
get
{
return singletonInstance;
}
set
{
singletonInstance = value;
}
}
/// <summary>
/// Re-initializes the singleton instance by causes the instance to be instantiated
/// as a new instance. This can be used, for example, when changes to configuration
/// have been made.
/// </summary>
/// <returns>A new instance of the type that sub-classes from this type</returns>
public static T Reinitialize()
{
lock (lockingObject)
{
SingletonInstance = null;
}
return GetInstance();
}
#endregion
}
An can be seen from the code, if an instance of the type that does exist than a
new instance is created by invoking the private constructor of that type.
The code for this method is shown below:
/// <summary>
Singleton derived classes must have a private or protected parameterless constructor.
/// Constructs a dynamic instance of the type T by invoking the
/// private or protected parameterless contructor of that type. This
/// primarily can be used to instantiate singleton instances (as by
/// definition they must not have a public constructor).
/// </summary>
/// <typeparam name="T">The type to instantiate</typeparam>
/// <returns>An instance of the type T</returns>
public static T ConstructParameterlessInstanceOfType<T>(BindingFlags bindingFlags) where T:class
{
ConstructorInfo constructor = typeof(T).GetConstructor(
bindingFlags,
null,
new Type[0],
new ParameterModifier[0]);
T instance = null;
if (constructor == null)
{
// Type does not have a private or protected parameterless constructor
throw new MemberAccessException(String.Format(CultureInfo.CurrentCulture, "Type {0} does not have the expected constructor (public or private parameterless constructor)", typeof(T).Name));
}
else
{
// Instantiate a new instance of the type by invoking the private or protected constructor
instance = constructor.Invoke(new object[0]) as T;
if (instance == null)
{
throw new MemberAccessException(String.Format(CultureInfo.CurrentCulture, "Unable to create an instance of the type {0}", typeof(T).Name));
}
}
return instance;
}
There is no check for a public constructor but this could easily be added.
Example
The following class demostrates how the is-a relationship can be established
with Singleton.
The two important points about the sample are:
/// <summary>
/// MicrosoftExceptionHandlingManager provides an exception handling
/// class that is coupled (uses) the Microsoft Patterns & Practices
/// library.
/// </summary>
public class MicrosoftExceptionHandlingManager : Singleton<MicrosoftExceptionHandlingManager>, IExceptionHandlingManager
{
#region CONSTRUCTORS
/// <summary>
/// Private constructor that is required in order for this to be
/// treated as a singleton
/// </summary>
private MicrosoftExceptionHandlingManager()
{
}
#endregion
#region METHODS
/// <summary>
/// Handles an exception by logging it to logging sinks as configured
/// using the Microsoft Enterprise Library V4.0. The specific way an exception
/// is handled can be specified by using the configuration tool that comes
/// supplied with the library.
/// </summary>
/// <param name="ex">The exception to handle</param>
/// <param name="exceptionHandlingPolicy">The policy to use for handling the exception (which relates to the policies in the configuration)</param>
public void LogException(Exception ex, string exceptionHandlingPolicy)
{
bool reThrow = ExceptionPolicy.HandleException(ex, exceptionHandlingPolicy);
if (reThrow == true)
{
throw ex;
}
}
#endregion
}
- The class is-a Singleton by deriving from Singleton and passing the class name as the type parameter.
- The class must have a private or protected constructor.
Testing Extension Points
MicrosoftExceptionHandlingManager.GetInstance()
- Performance testing as locking is used
- The GetInstance static methods checks that the type T does NOT have a public constructor