Incorporating Parameterized Construction in the Singleton Design Pattern






2.33/5 (2 votes)
Aug 6, 2003
3 min read

75577

2
How to incorporate parameterized construction in Microsoft's recommended implementation of a Singleton
Introduction
Many articles have been written about the Singleton design pattern and there have been a few on how to implement it in .NET. This article is not intended to be a restatement of those. Instead I want to describe a solution to a problem that occurred to me soon after reading Microsoft's recommended implementation of the Singleton pattern in .NET. The Microsoft solution was published in February 2002, titled Exploring the Singleton Design Pattern. Here it is:
// .NET Singleton
sealed class Singleton
{
private Singleton() {}
public static readonly Singleton Instance = new Singleton();
}
The traditional solution, as originally elaborated in Java, uses a technique called "double-check locking" in order to address thread safety. When translated to C# it looks like this:
// Double-Check Lock Singleton
class Singleton
{
public static Singleton Instance()
{
if (_instance == null)
{
lock (typeof(Singleton))
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
protected Singleton() {}
private static volatile Singleton _instance = null;
}
For a full discussion and explanation of the issues, and the above two solutions, please refer to the Microsoft article. Needless to say, Microsoft's recommended solution is far simpler than the traditional solution. But a problem occurred to me...
The Problem
What happens if I want to perform initialization of the singleton at
construction time? Well, in the traditional solution I can just overload the
Instance()
method to take parameters and this will delegate to an
overloaded protected constructor. So, for example, if I have a single WebMaster
object, I can write:
WebMaster webMaster = WebMaster.Instance("Kevin", "McFarlane");
However, with the recommended solution I can't do this. Instance
is
a read-only field, not a method, so I can't parameterize it. I'd been thinking
about this on and off for some time before I came up with
a reasonable solution. But I would be interested in seeing alternative
solutions.
At first I thought that the only way to do this was to make two separate calls along the following lines:
WebMaster webMaster = WebMaster.Instance;
webMaster.Create("Kevin", "McFarlane");
But this kind of thing is never ideal for a client. It's always preferable to have an object fully constructed at creation time. Or, if this is not possible, and further initialization needs to be done, this should be hidden from the client. Well, in the end, we can't really do this but we can improve matters. And the solution was virtually staring me in the face in the Microsoft example showing how to apply the recommended solution. Essentially we just arrange things so that the two separate calls can be combined into one. So, at least it looks like we're doing parameterized construction. Here's how:
// Singleton with "parameterised constructor"
sealed class WebMaster
{
public static readonly WebMaster Instance = new WebMaster();
public WebMaster Create(string firstName, string lastName)
{
_firstName = firstName;
_lastName = lastName;
return Instance;
}
public string FirstName
{
get
{
return _firstName;
}
}
public string LastName
{
get
{
return _lastName;
}
}
private WebMaster() {}
private string _firstName;
private string _lastName;
}
The Create
method serves as a "parameterized constructor." We can
now write code such as the following, which is more concise:
// Create a fully-constructed WebMaster instance
WebMaster webMaster = WebMaster.Instance.Create("Kevin", "McFarlane");
// Check its contents
Console.WriteLine("First Name = " + webMaster.FirstName);
Console.WriteLine("Last Name = " + webMaster.LastName);
Further Issues
If we wish to prevent multiple initialization through calling Create
more than once we can just add an internal flag to indicate whether the
instance has been "created" or not and raise an exception if it has.
But what if we wish to have only parameterized construction? That is,
what if we want to guarantee at compile time that the instance is
created in an initialized state? For example, suppose all instances of WebMaster
must have their name properties set. I can't see a way of doing this other than
by documentation. We can do better at runtime.
We could make every public routine, such as LastName
, check a flag
and then raise an exception if WebMaster
hasn't been
initialized.
This is something that can be done using conditionally compilable
precondition checking that we might disable for a release build.
Alternatively, if WebMaster
hasn't been initialized the fields
will be null. So when a client tries to use the name properties it will soon
notice that they haven't been set.
The latter approach is cleaner and simpler. We don't have to do anything. The former approach means more work but it has the advantage that the specification is made explicit and verifiable in code.