Google
 

Friday, March 9, 2007

A Singleton pattern variation

Singleton pattern is one of the famous creational design patterns in software.
The intent of this design pattern according to GoF is to:
ensure a class has only one instance, and provide a global point of access to it.

This is a simple implementation of this pattern in C#:
public class SingletonClass
{
private static SingletonClass _instance=null;
protected SingletonClass()
{
//
// TODO: Add constructor logic here
//
}

public static SingletonClass Instance()
{
if (_instance == null)
{
_instance = new SingletonClass();
}
return _instance;
}
}

This implementation depends on a static instance that is reused by all components within the same Application Domain. Sometimes, especially in web applications (which are multi threaded by nature), this can lead to problems, or it simply can be an undesirable behavior. For example, you may want to share this instance between all classes in the same request only.

To show that above technique will not give the required behavior, I a DateTime field to the class and set it in the constructor, then read it in a ASP.NET page code and display it.
public class SingletonClass
{
private static SingletonClass _instance=null;

private DateTime _creationTime;
protected SingletonClass()
{
_creationTime = DateTime.Now;
}

public DateTime GetCreationTime()
{
return _creationTime;
}

public static SingletonClass Instance()
{
if (_instance == null)
{
_instance = new SingletonClass();
}
return _instance;
}
}

And print this value in the Page_Load Event handler:
protected void Page_Load(object sender, EventArgs e)
{
SingletonClass c = SingletonClass.Instance();
Response.Write(c.GetCreationTime());
}

Try this page in different browser instances, notice that the response is always the same.

To make an instance shared at the request level, we have some candidates where to store it.
One is using thread local storage, which is an idea that I don't recommend after some research.
Another is to store the instance in the Http Context Items collection. This code is based on this idea:
public class SingletonClass
{
private DateTime _creationTime;
protected SingletonClass()
{
_creationTime = DateTime.Now;
}

public DateTime GetCreationTime()
{
return _creationTime;
}

public static SingletonClass Instance()
{
SingletonClass _instance=null;
if(!HttpContext.Current.Items.Contains(typeof(SingletonClass)))
{
_instance=new SingletonClass();
HttpContext.Current.Items.Add(typeof(SingletonClass),_instance);
}
else
{
_instance = (SingletonClass) HttpContext.Current.Items[typeof(SingletonClass)];
}
return _instance;

}
}
This code shows the technique in action:
protected void Page_Load(object sender, EventArgs e)
{
SingletonClass a = SingletonClass.Instance();
System.Threading.Thread.Sleep(1000);
SingletonClass b = SingletonClass.Instance();

Response.Write(a.GetCreationTime().Ticks);

Response.Write(" , ");
Response.Write(b.GetCreationTime().Ticks);
}

Note that the same instance is used in the life time of the request, and when you open the page in a new browser instance or refresh the same page,you'll see that a new instance was created for the new request.

No comments: