A Singleton class is one that allows only one instance of it
to be created in the lifetime of an application. This article discusses the
singleton pattern, one of the most well known patterns in software engineering
with lucid examples.
What is a Singleton Class?
A singleton class is one that can be instantiated only once in
the application domain and provides a global point of access to it. In this
article we would implement a StateManager class that manages the storage and/or
retrieval of objects in the Cache, Application and Session. We require only one
instance of this class to be created throughout the application’s lifetime.
Implementing the Singleton Pattern
We declare an enum called State that holds the following values:
·
Application
·
Session
·
Cache
·
ViewState
The enum is as given below:
Listing I: The State enum
public enum State
{
Application,Session,Cache,ViewState
}
The StateManager class shown below manages the storage
and/or retrieval of objects to the states mentioned above. The class is sealed
to help JIT in optimization and contains a private constructor to prevent
instantiation directly.
Listing II: The StateManager class
public sealed class StateManager
{
private static StateManager obj =null;
private System.Web.UI.StateBagViewState = new StateBag();
private StateManager()
{
}
public static StateManager Instance
{
get
{
if(obj == null)
obj = newStateManager();
return obj;
}
}
public void Add(string key,objectdata,State state)
{
switch(state)
{
case State.Application:
HttpContext.Current.Application.Add(key,data);
break;
case State.Session:
HttpContext.Current.Session.Add(key,data);
break;
case State.Cache:
HttpContext.Current.Cache.Insert(key,data);
break;
case State.ViewState:ViewState.Add(key,data);
break;
}
}
public void Remove(string key,Statestate)
{
switch(state)
{
case State.Application:
if(HttpContext.Current.Application[key]
!= null)
HttpContext.Current.Application.
Remove(key);
break;
case State.Session:
if(HttpContext.Current.Session[key] !=
null)
HttpContext.Current.Session.Remove(key);
break;
case State.Cache:
if(HttpContext.Current.Cache[key] !=
null)
HttpContext.Current.Cache.Remove(key);
break;
case State.ViewState:
if(ViewState [key]!= null)
ViewState.Remove(key);
break;
}
}
public object Get(string key,Statestate)
{
switch(state)
{
case State.Application:
if(HttpContext.Current.Application[key]
!= null)
returnHttpContext.Current.
Application[key];
break;
case State.Session:
if(HttpContext.Current.Session[key] !=
null)
returnHttpContext.Current.Session[key];
break;
case State.Cache:
if(HttpContext.Current.Cache[key] !=
null)
returnHttpContext.Current.Cache[key];
break;
case State.ViewState:
if(ViewState[key]!= null)
returnViewState[key];
break;
default: return null;
}
return null;
}
public int Count(State state)
{
switch(state)
{
case State.Application:
if(HttpContext.Current.Application!=
null)
returnHttpContext.Current.Application.
Count;
break;
case State.Session:
if(HttpContext.Current.Session!= null)
returnHttpContext.Current.Session.Count;
break;
case State.Cache:
if(HttpContext.Current.Cache!= null)
returnHttpContext.Current.Cache.Count;
break;
case State.ViewState:
if(ViewState != null)
return ViewState.Count;
break;
default:
return 0;
}
return 0;
}
}
The method Add stores objects in the respective states based
value on the object of the State enum as parameter. The Remove method removes
the objects and the Count method is responsible for returning the number of
objects stored in these states. This implementation is not thread safe,
however. There can be two threads trying to access the property instance at the
same point of time. If both of these threads evaluated the condition if(obj ==
null) and found it true, then both would have created the objects which would
violate the pattern. Hence, we should have some way of providing thread safety
to the creation of the object of this class. The following code is a thread
safe version of the same class.
Listing III: The thread safe and lazy State Manager
class.
using System;
using System.Web;
using System.Web.UI;
namespace UtilityLibrary
{
public enum State
{
Application,Session,Cache,ViewState
}
public sealed class StateManager
{
private static readonly StateManagerobj = new
StateManager();
private System.Web.UI.StateBagViewState = new StateBag();
private StateManager()
{
}
static StateManager()
{
}
public static StateManager Instance
{
get
{
return obj;
}
}
public void Add(string key,objectdata,State state)
{
switch(state)
{
case State.Application:
HttpContext.Current.Application.Add(key,data);
break;
case State.Session:
HttpContext.Current.Session.Add(key,data);
break;
case State.Cache:
HttpContext.Current.Cache.Insert(key,data);
break;
case State.ViewState:ViewState.Add(key,data);
break;
}
}
public void Remove(string key,Statestate)
{
switch(state)
{
case State.Application:
if(HttpContext.Current.Application[key]
!= null)
HttpContext.Current.Application.
Remove(key);
break;
case State.Session:
if(HttpContext.Current.Session[key] !=
null)
HttpContext.Current.Session.Remove(key);
break;
case State.Cache:
if(HttpContext.Current.Cache[key] !=
null)
HttpContext.Current.Cache.Remove(key);
break;
caseState.ViewState:
if(ViewState [key]!= null)
ViewState.Remove(key);
break;
}
}
public object Get(string key,Statestate)
{
switch(state)
{
case State.Application:
if(HttpContext.Current.Application[key]
!= null)
returnHttpContext.Current.
Application[key];
break;
case State.Session:
if(HttpContext.Current.Session[key] !=
null)
returnHttpContext.Current.Session[key]; break;
case State.Cache:
if(HttpContext.Current.Cache[key] !=
null)
returnHttpContext.Current.Cache[key];
break;
case State.ViewState:
if(ViewState[key]!= null)
returnViewState[key];
break;
default: return null;
}
return null;
}
public int Count(State state)
{
switch(state)
{
case State.Application:
if(HttpContext.Current.Application!=
null)
returnHttpContext.Current.Application.
Count;
break;
case State.Session:
if(HttpContext.Current.Session!= null)
returnHttpContext.Current.Session.Count;
break;
case State.Cache:
if(HttpContext.Current.Cache!= null)
returnHttpContext.Current.Cache.Count;
break;
case State.ViewState:
if(ViewState !=null)
returnViewState.Count;
break;
default: return 0;
}
return 0;
}
}
}
The StateManager object in the above listing is static and
readonly. A static readonly object can be instantiated only using a variable
initializer or a static constructor.
It is to be noted that the C# compiler marks all types as
beforefieldinit if they contain only non - static constructors. A laziness of a
type depends on whether or not the type is marked as beforefieldinit. As shown
in the example above, the static constructor is specified as it would be
executed only once during the lifetime of the application and does not mark the
type as beforefieldinit. This promises laziness. We do not require explicit
locks in the example above, but it still is type safe. There is no requirement
of checking whether the instance is null, as in the previous version of the
StateManager class in Listing I.
Using the State Manager class
The following code shows how we can use the class designed
above in our code.
Listing IV: Using the State Manager class
private void Page_Load(object sender,System.EventArgs e)
{
StateManager stateManager =StateManager.Instance;
stateManager.Add("jk","Joydip",State.Session);
if(stateManager.Get("jk",State.Session)!=null)
}
Further Reading
Please refer to the following links for more related
information:
http://www.dofactory.com/Patterns/PatternSingleton.aspx
http://www.yoda.arachsys.com/csharp/singleton.html
Conclusion
Design patterns are a solution to the complexities in
software architecture. A good knowledge of design pattern goes a long way to
solving the complexities that are faced in software designs. This article has
discussed the Singleton Design Pattern, a pattern that falls under the
Creational Patterns. Please send me your feedback.