RS Prajapati, 28 Dec 2014
|
|
|
Introduction
The
Singleton pattern is probably the most famous and at the same time the most
controversial pattern known to us. It must be also be the simplest pattern to
learn and implement. Like any other pattern, Singleton exists to solve a common
business problem that is ‘managing the state of a resource’. But does it solve
the real problem or introduce additional problems? That is exactly the topic I
am covering here.
Positive Sides of Singleton
One
of the toughest issues to debug is the one created by the multiple instances of
a class which manages the state of a single resource. It is highly desirable if
we can use some Design Pattern to control the access to that shared resource.
The Singleton pattern fits the bill perfectly to solve this scenario; by
wrapping a singleton class around this problem ensures that there will be only
one instance of the class at any given time. A most common and clichéd example
for a singleton class is the one used for logging purposes where the whole
application needs only one logger instance at anytime.
The
anatomy of a singleton class is very simple to understand. The class typically
has a private constructor which will prohibit you to make any instance
of the singleton class; instead you will access a static property or static function of the
singleton class to get the reference of a preconfigured instance. These
properties/methods ensure that there will be only one instance of the singleton
class throughout the lifetime of the application.
The
one and only instance of a singleton class is created within the singleton
class and its reference is consumed by the callers. The creation process of the
instance can be done using any of the following methods:
1. Lazy Instantiation
If
you opt for the lazy instantiation paradigm, then the singleton variable will
not get memory until the property or function designated to return the
reference is first called. This type of instantiation is very helpful if your
singleton class is resource intense.
However,
the above implementation is not taking any precautions to be thread safe. That
is, there may be situations like two or more threads accessing the Instance property at the
same time which will create more than one instance of the singleton class.
We
can use various thread synchronization techniques to combat the circumstances
said above. One way is the use of double-checked locking. In double-checked
locking, synchronization is only effective when the singleton variable is null, i.e., only for the first
time call to Instance. This helps us to limit the performance penalty that comes
along with the synchronization object to only happen once.
2. Static Initialization
In
static initialization, memory is allocated to the variable at the time it is
declared. The instance creation takes place behind the scenes when any of the
member singleton classes is accessed for the first time. The main advantage of
this type of implementation is that the CLR automatically takes care of race
conditions I explained in lazy instantiation. We don't have to use any special
synchronization constructs here. There are no significant code changes in the
singleton implementation when you switch from lazy instantiation to static
initialization. The only change is that the object creation part is moved to
the place where we are declaring the variable.
Inheritance of Singleton Class
Inheriting
a singleton class should be prohibited. Making a singleton class inheritable
means any number of child classes can inherit from it creating multiple
instances of the singleton class which will obviously violate the principle of
singletons.
Singleton Class vs. Static Methods
Singleton
takes over static classes on the following shortcomings:
1. Static classes don’t
promote inheritance. If your class has some interface to derive from, static classes makes it
impossible.
2. You cannot specify any creation logic with static methods.
3. Static methods are
procedural code.
Negative Sides of Singleton
The
following points are used against the Singleton pattern:
1. They deviate from the Single Responsibility
Principle. A singleton class has the responsibility to create an instance of
itself along with other business responsibilities. However, this issue can be
solved by delegating the creation part to a factory object.
2. Singleton classes cannot be sub classed.
3. Singletons can hide dependencies. One of the
features of an efficient system architecture is minimizing dependencies between
classes. This will in turn help you while conducting unit tests and while
isolating any part of the program to a separate assembly. A singleton will make
you sacrifice this feature in your application. Since the object creation part
is invisible to us, we cannot expect the singleton constructor to accept any
parameters. This setback may look unimportant on the first glance but as the
software complexity increases, it will limit the flexibility of the program.
Programmers
often resort to the idea of Dependency Injection to overcome this problem. When
dependency Injection is used, Singleton instance is not retrieved inside the
class but is passed through the constructor or a property
Hide Copy Code
IMathFace obj = Singleton.Instance;
SingletonConsumer singConsumer = new SingletonConsumer(obj);
singConsumer.ConsumerAdd(10,20);
In
the above example, SingletonConsumer's constructor accepts a parameter of type IMathFace. It can be the real
singleton instance or a mock object.
When to Use a Singleton Class?
There
is no straightforward answer to this question. A scenario which is acceptable
to some will be unacceptable to others.
However,
it is commonly accepted that the singleton can yield best results in a
situation where various parts of an application concurrently try to access a
shared resource. An example of a shared resource would be Logger, Print Spooler, etc.
The
following points are suggested to be considered while designing a singleton
class:
1. Singleton classes must be memory-leak free.
The instance of the singleton class is to be created once and it remains for
the lifetime of the application.
2. A real singleton class is not easily
extensible.
3. Derive the singleton class from an interface.
This helps while doing unit testing (using Dependency Injection).
Conclusion
The
notion of Singleton pattern replacing global variables is not always true. You
should keep all the positive and negative aspects of the Singleton pattern in
mind before deciding on it.
No comments:
Post a Comment