Definition:
Singleton is
a part of Gang of Four design pattern
and it is categorized under creational design patterns. In this article we are
going to take a deeper look into the usage of the Singleton pattern. It is one
of the most simple design pattern in terms of the modelling but on the other
hand this is one of the most controversial pattern in terms of complexity of
usage.
In Java the Singleton pattern will ensure that there is only one instance of a
class is created in the Java Virtual Machine. It is used to provide global
point of access to the object. In terms of practical use Singleton patterns are
used in logging, caches, thread pools, configuration settings, device driver
objects. Design pattern is often used in conjunction with Factory design pattern. This pattern is also
used in Service Locator JEE pattern.
Structure:
Singleton Class Diagram
§ Private constructor : This will prevent
anybody else to instantiate the Singleton class.
§ Static public method : This provides the
global point of access to the Singleton object and returns the instance to the
client calling class.
Implementation Example: Lazy initialization
Let us look into a singleton implementation
example in Java. The below code uses Lazy initialization process.
Code:
public class SingletonExample {
// Static
member holds only one instance of the
//
SingletonExample class
private static
SingletonExample singletonInstance;
//
SingletonExample prevents any other class from instantiating
private SingletonExample()
{
}
//
Providing Global point of access
public static
SingletonExample getSingletonInstance() {
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
}
return
singletonInstance;
}
public void
printSingleton(){
System.out.println("Inside
print Singleton");
}
}
Singleton Pattern Code Explanation
When this class will be called from the client
side using SingletonExample.getSingletonInstance().printSingleton();then
at the first time only an instance will be created. During second time onwards
for all subsequent calls we will be referring to the same object and the getSingletonInstance() method
returns the same instance of the SingletonExample class which was created
during the first time. You can test this by adding a print statement the
following code as :
Code:
public static SingletonExample
getSingletonInstance() {
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
System.out.println("Creating
new instance");
}
return
singletonInstance;
}
If we now call Singleton class from the client
class as:
Code:
SingletonExample.getSingletonInstance().printSingleton();
SingletonExample.getSingletonInstance().printSingleton();
SingletonExample.getSingletonInstance().printSingleton();
SingletonExample.getSingletonInstance().printSingleton();
The output of the above call is:
Code:
Creating new instance
Inside print Singleton
Inside print Singleton
Inside print Singleton
Inside print Singleton
Implementation Example: Double check locking
The above code works absolutely fine in a
single threaded environment and processes the result faster because of lazy
initialization. However the above code might create some abrupt behaviour in
the results in a multithreaded environment as in this situation multiple
threads can possibly create multiple instance of the same SingletonExample
class if they try to access the getSingletonInstance() method
at the same time. Imagine a practical scenario where we have to create a log
file and update it or while using a shared resource like Printer. To prevent
this we must use some locking mechanism so that the second thread cannot use
this getInstance() method until the first thread has completed
the process.
Singleton in heap
In Figure 3 we show how multiple threads
access the singleton instance. Since the singleton instance is a static class
variable in the stored in the PermGen space of the heap. This applies to getSingletonInstance() instance
method as well since it is static too. In the multithreading environment to
prevent each thread to create another instance of singleton object and thus
creating concurrency issue we will need to use locking mechanism. This can be
achieved by synchronized keyword. By using this synchronized keyword we prevent
Thread2 or Thread3 to access the singleton instance while Thread1 inside the
method getSingletonInstance().
From code perspective it means:
Code:
public static synchronized SingletonExample
getSingletonInstance() {
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
}
return
singletonInstance;
}
So this means that every time the getSingletonInstance() is
called it gives us an additional overhead . To prevent this expensive operation
we will use double checked locking so that the synchronization
happens only during the first call and we limit this expensive operation to
happen only once. It is only required for :
Code:
singletonInstance = new SingletonExample();
Code example:
Code:
public static SingletonExample
getSingletonInstance() {
if
(null == singletonInstance) {
synchronized
(SingletonExample.class){
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
}
}
}
return
singletonInstance;
}
In the above code snippet imagine that
multiple threads comes concurrently and tries to create the new instance. In
such situation the may be three or more threads are waiting on the synchronized
block to get access. Since we have used synchronized only one thread will be
given access. All the remaining threads which were waiting on the synchronized
block will be given access when first thread exits this block. However when the
remaining concurrent thread enters the synchronized block they are prevented to
enter further due to the double check : null check. Since the first thread has
already created an instance no other thread will enter this loop.
All the remaining threads that were not lucky
to enter the synchronized block along with the first thread will be blocked at
the first null check. This mechanism is called double checked locking and
it provides significant performance benefit and also it is cost effective
solution.
Implementation Example: Volatile Keyword
We can also use the volatile keyword to the
instance variable declaration.
Code:
private volatile static SingletonExample
singletonInstance;
The volatile keyword helps as concurrency
control tool in a multithreaded environment and provides the latest update in a
most accurate manner.However please note that double check locking might not
work before Java 5. In such situation we can use early loading mechanism. If we
remember about the original sample code we had used lazy loading. In case of
early loading we will instantiate the SingletonExample class at the start and
this will be referred to the private static instance field.
Code:
public class SingletonExample {
private static
final SingletonExample singletonInstance = new SingletonExample;
//
SingletonExample prevents any other class from instantiating
private SingletonExample()
{
}
//
Providing Global point of access
public static
SingletonExample getSingletonInstance() {
return
singletonInstance;
}
public void
printSingleton(){
System.out.println("Inside
print Singleton");
}
}
In this approach the singleton object is
created before it is needed. The JVM takes care of the static variable
initialization and ensures that the process is thread safe and that the
instance is created before the threads tries to access it. In case of Lazy
loading the singletonInstance is created when the client class
calls the getSingleInstance()whereas in case of the early loading
the singletonInstance is create when the class is loaded in the memory.
Implementation Example: Using enum
Implementing Singleton in Java 5 or above
version using Enum:
Enum is thread safe and implementation of Singleton through Enum ensures that
your singleton will have only one instance even in a multithreaded environment.
Let us see a simple implementation:
Code:
public enum SingletonEnum {
INSTANCE;
public void doStuff(){
System.out.println("Singleton
using Enum");
}
}
And this can be called from
clients :
public static void main(String[]
args) {
SingletonEnum.INSTANCE.doStuff();
}
FAQs:
Question: Why can’t we use a static class
instead of singleton?
Answer:
§ One of the key advantages of singleton over
static class is that it can implement interfaces and extend classes while the
static class cannot (it can extend classes, but it does not inherit their
instance members). If we consider a static class it can only be a nested static
class as top level class cannot be a static class. Static means that it belongs
to a class it is in and not to any instance. So it cannot be a top level class.
§ Another difference is that static class will
have all its member as static only unlike Singleton.
§ Another advantage of Singleton is that it can
be lazily loaded whereas static will be initialized whenever it is first
loaded.
§ Singleton object stores in Heap but, static
object stores in stack.
§ We can clone the object of Singleton but, we
can not clone the static class object.
§ Singleton can use the Object Oriented feature
of polymorphism but static class cannot.
Question: Can the singleton class be
subclassed?
Answer: Frankly speaking singleton is just a design pattern and it can be subclassed.
However it is worth to understand the logic or requirement behind subclassing a
singleton class as the child class might not inherit the singleton pattern
objective by extending the Singleton class. However the subclassing can be
prevented by using the final keyword in the class declaration.
Question: Can there be multiple instance of
singleton using cloning?
Answer: That was a good catch! What do we do now? To prevent the another
instance to be created of the singleton instance we can throw exception from
inside the clone() method.
Question: What is the impact if we are
creating another instance of singleton using serialization and deserialization?
Answer: When we serialize a class and deserialize it then it creates another
instance of the singleton class. Basically as many times as you deserialize the
singleton instance it will create multiple instance. Well in this case the best
way is to make the singleton as enum. In that way the underlying Java
implementation takes care of all the details. If this is not possible then we
will need to override the readobject() method to return the
same singleton instance.
Question: Which other pattern works with
Singleton?
Answer:There are several other pattern like Factory method, builder and
prototype pattern which uses Singleton pattern during the implementation.
Question: Which classes in JDK uses singleton
pattern?
Answer: java.lang.Runtime : In every Java application there is only one Runtime
instance that allows the application to interface with the environment it is
running. The getRuntime is equivalent to the getInstance() method of the
singleton class.
Uses of Singleton design pattern:
Various usages of Singleton Patterns:
§ Hardware interface access: The use of
singleton depends on the requirements. However practically singleton can be
used in case external hardware resource usage limitation required e.g. Hardware
printers where the print spooler can be made a singleton to avoid multiple
concurrent accesses and creating deadlock.
§ Logger : Similarly singleton is a good
potential candidate for using in the log files generation. Imagine an
application where the logging utility has to produce one log file based on the
messages received from the users. If there is multiple client application using
this logging utility class they might create multiple instances of this class
and it can potentially cause issues during concurrent access to the same logger
file. We can use the logger utility class as a singleton and provide a global
point of reference.
§ Configuration File: This is another potential
candidate for Singleton pattern because this has a performance benefit as it
prevents multiple users to repeatedly access and read the configuration file or
properties file. It creates a single instance of the configuration file which
can be accessed by multiple calls concurrently as it will provide static config
data loaded into in-memory objects. The application only reads from the
configuration file at the first time and there after from second call onwards
the client applications read the data from in-memory objects.
§ Cache: We can use the cache as a singleton
object as it can have a global point of reference and for all future calls to
the cache object the client application will use the in-memory object.
Hands-on:
Let us take a small practical example to
understand the Singleton design pattern in more details.
Problem Statement:
Design a small ATM printing application which can generate multiple types of
statements of the transaction including Mini Statement, Detailed statement etc.
However the customer should be aware of the creation of these statements.
Ensure that the memory consumption is minimized.
Design Solution:
The above requirement can be addressed using two core Gang of four design
pattern – Factory design pattern and Singleton design pattern. In order to
generate multiple types of statements for the ATM transactions in the ATM
machine we can create a Statement Factory object which will have a factory
method of createStatements(). The createStatements will create
DetailedStatement or MiniStatement objects. The client object will be
completely unware of the object creation since it will interact with the
Factory interface only. We will also create an interface called StatementType.
This will allow further statement type objects e.g. Credit card statement etc
to be added. So the solution is scalable and extensible following the object
oriented Open/Closed design principle.
The second requirement of reducing the memory consumption can be achieved by
using Singleton design pattern. The Statement Factory class need not be
initiated multiple times and a single factory can create multiple statement
objects. Singleton pattern will create a single instance of the
StatementFactory class thus saving memory.
ATM example
§ Factory: Factory is an abstract class which is
a single point of contact for the client. All the concrete factory classes
needs to implement the abstract factory method.
§ StatementFactory: This is the Factory
implementation class which consist of the creator method. This class extends
from the Factory abstract class.This is the main creator class for all the
products e.g. Statements.
§ StatementType: This is a product interface
which provides abstraction to the various types of products which needs to be
created by the Factory class.
§ DetailedStatement: This is a concrete implementation
of the StatementType interface which will print the detailed statements.
§ MiniStatement: This is a concrete
implementation of the StatementType interface which will print the mini
statements.
§ Client: This is the client class which will
call the StatementFactory and StatementType and request for object creation.
Assumption:
The design solution caters to only single ATM machine.
Sample Code:
Factory.java
Code:
public abstract class Factory {
protected abstract StatementType
createStatements(String selection);
}
StatementFactory.java
Code:
public class StatementFactory
extends Factory {
private static
StatementFactory uniqueInstance;
private StatementFactory()
{
}
public static
StatementFactory getUniqueInstance() {
if
(uniqueInstance == null) {
uniqueInstance
= new StatementFactory();
System.out.println("Creating
a new StatementFactory instance");
}
return
uniqueInstance;
}
public StatementType
createStatements(String selection) {
if
(selection.equalsIgnoreCase("detailedStmt")) {
return
new DetailedStatement();
}
else if (selection.equalsIgnoreCase("miniStmt")) {
return
new MiniStatement();
}
throw
new IllegalArgumentException("Selection doesnot exist");
}
}
StatementType.java
Code:
public interface StatementType {
String
print();
}
DetailedStatement.java
Code:
public class DetailedStatement
implements StatementType {
@Override
public String
print() {
System.out.println("Detailed
Statement Created");
return
"detailedStmt";
}
}
MiniStatement.java
Code:
public class MiniStatement
implements StatementType {
@Override
public String
print() {
System.out.println("Mini
Statement Created");
return
"miniStmt";
}
}
Client.java
Code:
public class Client {
public static
void main(String[] args) {
System.out.println("Enter
your selection:");
BufferedReader
br = new BufferedReader(new InputStreamReader(System.in));
String
selection = null;
try
{
selection
= br.readLine();
}
catch (IOException e) {
e.printStackTrace();
}
Factory
factory = StatementFactory.getUniqueInstance();
StatementType
objStmtType = factory.createStatements(selection);
System.out.println(objStmtType.print());
}
}
Conclusion:
In the above articles we have gone into the
details of the Singleton pattern, how to implement singleton pattern along with
a practical application. Though singleton pattern looks a simple implementation
we should resist ourselves from using it until and unless there is a strong
requirement for it. You can blame the unpredictable nature of the results in
the multi-threading environment. Though we can use enum in
Java 5 and above it sometimes get difficult to implement your logic always in enum or
there might be legacy code before Java 5. Hope our readers have liked this
article.
Reference: Singleton Design
Pattern – An introspection and best practices from our JCG partner Mainak Goswami at the Idiotechieblog
Definition:
Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns. In this article we are going to take a deeper look into the usage of the Singleton pattern. It is one of the most simple design pattern in terms of the modelling but on the other hand this is one of the most controversial pattern in terms of complexity of usage.
In Java the Singleton pattern will ensure that there is only one instance of a class is created in the Java Virtual Machine. It is used to provide global point of access to the object. In terms of practical use Singleton patterns are used in logging, caches, thread pools, configuration settings, device driver objects. Design pattern is often used in conjunction with Factory design pattern. This pattern is also used in Service Locator JEE pattern.
Structure:
Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns. In this article we are going to take a deeper look into the usage of the Singleton pattern. It is one of the most simple design pattern in terms of the modelling but on the other hand this is one of the most controversial pattern in terms of complexity of usage.
In Java the Singleton pattern will ensure that there is only one instance of a class is created in the Java Virtual Machine. It is used to provide global point of access to the object. In terms of practical use Singleton patterns are used in logging, caches, thread pools, configuration settings, device driver objects. Design pattern is often used in conjunction with Factory design pattern. This pattern is also used in Service Locator JEE pattern.
Structure:
Singleton Class Diagram
§ Private constructor : This will prevent
anybody else to instantiate the Singleton class.
§ Static public method : This provides the
global point of access to the Singleton object and returns the instance to the
client calling class.
Implementation Example: Lazy initialization
Let us look into a singleton implementation
example in Java. The below code uses Lazy initialization process.
Code:
|
|
public class SingletonExample {
// Static
member holds only one instance of the
//
SingletonExample class
private static
SingletonExample singletonInstance;
//
SingletonExample prevents any other class from instantiating
private SingletonExample()
{
}
//
Providing Global point of access
public static
SingletonExample getSingletonInstance() {
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
}
return
singletonInstance;
}
public void
printSingleton(){
System.out.println("Inside
print Singleton");
}
}
|
Singleton Pattern Code Explanation
When this class will be called from the client
side using SingletonExample.getSingletonInstance().printSingleton();then
at the first time only an instance will be created. During second time onwards
for all subsequent calls we will be referring to the same object and the getSingletonInstance() method
returns the same instance of the SingletonExample class which was created
during the first time. You can test this by adding a print statement the
following code as :
Code:
|
|
public static SingletonExample
getSingletonInstance() {
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
System.out.println("Creating
new instance");
}
return
singletonInstance;
}
|
If we now call Singleton class from the client
class as:
Code:
|
|
SingletonExample.getSingletonInstance().printSingleton();
SingletonExample.getSingletonInstance().printSingleton();
SingletonExample.getSingletonInstance().printSingleton();
SingletonExample.getSingletonInstance().printSingleton();
|
The output of the above call is:
Code:
|
|
Creating new instance
Inside print Singleton
Inside print Singleton
Inside print Singleton
Inside print Singleton
|
Implementation Example: Double check locking
The above code works absolutely fine in a
single threaded environment and processes the result faster because of lazy
initialization. However the above code might create some abrupt behaviour in
the results in a multithreaded environment as in this situation multiple
threads can possibly create multiple instance of the same SingletonExample
class if they try to access the getSingletonInstance() method
at the same time. Imagine a practical scenario where we have to create a log
file and update it or while using a shared resource like Printer. To prevent
this we must use some locking mechanism so that the second thread cannot use
this getInstance() method until the first thread has completed
the process.
Singleton in heap
In Figure 3 we show how multiple threads
access the singleton instance. Since the singleton instance is a static class
variable in the stored in the PermGen space of the heap. This applies to getSingletonInstance() instance
method as well since it is static too. In the multithreading environment to
prevent each thread to create another instance of singleton object and thus
creating concurrency issue we will need to use locking mechanism. This can be
achieved by synchronized keyword. By using this synchronized keyword we prevent
Thread2 or Thread3 to access the singleton instance while Thread1 inside the
method getSingletonInstance().
From code perspective it means:
Code:
|
|
public static synchronized SingletonExample
getSingletonInstance() {
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
}
return
singletonInstance;
}
|
So this means that every time the getSingletonInstance() is
called it gives us an additional overhead . To prevent this expensive operation
we will use double checked locking so that the synchronization
happens only during the first call and we limit this expensive operation to
happen only once. It is only required for :
Code:
|
|
singletonInstance = new SingletonExample();
|
Code example:
Code:
|
|
public static SingletonExample
getSingletonInstance() {
if
(null == singletonInstance) {
synchronized
(SingletonExample.class){
if
(null == singletonInstance) {
singletonInstance
= new SingletonExample();
}
}
}
return
singletonInstance;
}
|
In the above code snippet imagine that
multiple threads comes concurrently and tries to create the new instance. In
such situation the may be three or more threads are waiting on the synchronized
block to get access. Since we have used synchronized only one thread will be
given access. All the remaining threads which were waiting on the synchronized
block will be given access when first thread exits this block. However when the
remaining concurrent thread enters the synchronized block they are prevented to
enter further due to the double check : null check. Since the first thread has
already created an instance no other thread will enter this loop.
All the remaining threads that were not lucky
to enter the synchronized block along with the first thread will be blocked at
the first null check. This mechanism is called double checked locking and
it provides significant performance benefit and also it is cost effective
solution.
Implementation Example: Volatile Keyword
We can also use the volatile keyword to the
instance variable declaration.
Code:
|
|
private volatile static SingletonExample
singletonInstance;
|
The volatile keyword helps as concurrency
control tool in a multithreaded environment and provides the latest update in a
most accurate manner.However please note that double check locking might not
work before Java 5. In such situation we can use early loading mechanism. If we
remember about the original sample code we had used lazy loading. In case of
early loading we will instantiate the SingletonExample class at the start and
this will be referred to the private static instance field.
Code:
|
|
public class SingletonExample {
private static
final SingletonExample singletonInstance = new SingletonExample;
//
SingletonExample prevents any other class from instantiating
private SingletonExample()
{
}
//
Providing Global point of access
public static
SingletonExample getSingletonInstance() {
return
singletonInstance;
}
public void
printSingleton(){
System.out.println("Inside
print Singleton");
}
}
|
In this approach the singleton object is
created before it is needed. The JVM takes care of the static variable
initialization and ensures that the process is thread safe and that the
instance is created before the threads tries to access it. In case of Lazy
loading the singletonInstance is created when the client class
calls the getSingleInstance()whereas in case of the early loading
the singletonInstance is create when the class is loaded in the memory.
Implementation Example: Using enum
Implementing Singleton in Java 5 or above
version using Enum:
Enum is thread safe and implementation of Singleton through Enum ensures that your singleton will have only one instance even in a multithreaded environment. Let us see a simple implementation:
Enum is thread safe and implementation of Singleton through Enum ensures that your singleton will have only one instance even in a multithreaded environment. Let us see a simple implementation:
Code:
|
|
public enum SingletonEnum {
INSTANCE;
public void doStuff(){
System.out.println("Singleton
using Enum");
}
}
And this can be called from
clients :
public static void main(String[]
args) {
SingletonEnum.INSTANCE.doStuff();
}
|
FAQs:
Question: Why can’t we use a static class
instead of singleton?
Answer:
Answer:
§ One of the key advantages of singleton over
static class is that it can implement interfaces and extend classes while the
static class cannot (it can extend classes, but it does not inherit their
instance members). If we consider a static class it can only be a nested static
class as top level class cannot be a static class. Static means that it belongs
to a class it is in and not to any instance. So it cannot be a top level class.
§ Another difference is that static class will
have all its member as static only unlike Singleton.
§ Another advantage of Singleton is that it can
be lazily loaded whereas static will be initialized whenever it is first
loaded.
§ Singleton object stores in Heap but, static
object stores in stack.
§ We can clone the object of Singleton but, we
can not clone the static class object.
§ Singleton can use the Object Oriented feature
of polymorphism but static class cannot.
Question: Can the singleton class be
subclassed?
Answer: Frankly speaking singleton is just a design pattern and it can be subclassed. However it is worth to understand the logic or requirement behind subclassing a singleton class as the child class might not inherit the singleton pattern objective by extending the Singleton class. However the subclassing can be prevented by using the final keyword in the class declaration.
Answer: Frankly speaking singleton is just a design pattern and it can be subclassed. However it is worth to understand the logic or requirement behind subclassing a singleton class as the child class might not inherit the singleton pattern objective by extending the Singleton class. However the subclassing can be prevented by using the final keyword in the class declaration.
Question: Can there be multiple instance of
singleton using cloning?
Answer: That was a good catch! What do we do now? To prevent the another instance to be created of the singleton instance we can throw exception from inside the clone() method.
Answer: That was a good catch! What do we do now? To prevent the another instance to be created of the singleton instance we can throw exception from inside the clone() method.
Question: What is the impact if we are
creating another instance of singleton using serialization and deserialization?
Answer: When we serialize a class and deserialize it then it creates another instance of the singleton class. Basically as many times as you deserialize the singleton instance it will create multiple instance. Well in this case the best way is to make the singleton as enum. In that way the underlying Java implementation takes care of all the details. If this is not possible then we will need to override the readobject() method to return the same singleton instance.
Answer: When we serialize a class and deserialize it then it creates another instance of the singleton class. Basically as many times as you deserialize the singleton instance it will create multiple instance. Well in this case the best way is to make the singleton as enum. In that way the underlying Java implementation takes care of all the details. If this is not possible then we will need to override the readobject() method to return the same singleton instance.
Question: Which other pattern works with
Singleton?
Answer:There are several other pattern like Factory method, builder and prototype pattern which uses Singleton pattern during the implementation.
Answer:There are several other pattern like Factory method, builder and prototype pattern which uses Singleton pattern during the implementation.
Question: Which classes in JDK uses singleton
pattern?
Answer: java.lang.Runtime : In every Java application there is only one Runtime instance that allows the application to interface with the environment it is running. The getRuntime is equivalent to the getInstance() method of the singleton class.
Answer: java.lang.Runtime : In every Java application there is only one Runtime instance that allows the application to interface with the environment it is running. The getRuntime is equivalent to the getInstance() method of the singleton class.
Uses of Singleton design pattern:
Various usages of Singleton Patterns:
§ Hardware interface access: The use of
singleton depends on the requirements. However practically singleton can be
used in case external hardware resource usage limitation required e.g. Hardware
printers where the print spooler can be made a singleton to avoid multiple
concurrent accesses and creating deadlock.
§ Logger : Similarly singleton is a good
potential candidate for using in the log files generation. Imagine an
application where the logging utility has to produce one log file based on the
messages received from the users. If there is multiple client application using
this logging utility class they might create multiple instances of this class
and it can potentially cause issues during concurrent access to the same logger
file. We can use the logger utility class as a singleton and provide a global
point of reference.
§ Configuration File: This is another potential
candidate for Singleton pattern because this has a performance benefit as it
prevents multiple users to repeatedly access and read the configuration file or
properties file. It creates a single instance of the configuration file which
can be accessed by multiple calls concurrently as it will provide static config
data loaded into in-memory objects. The application only reads from the
configuration file at the first time and there after from second call onwards
the client applications read the data from in-memory objects.
§ Cache: We can use the cache as a singleton
object as it can have a global point of reference and for all future calls to
the cache object the client application will use the in-memory object.
Hands-on:
Let us take a small practical example to
understand the Singleton design pattern in more details.
Problem Statement:
Design a small ATM printing application which can generate multiple types of statements of the transaction including Mini Statement, Detailed statement etc. However the customer should be aware of the creation of these statements. Ensure that the memory consumption is minimized.
Design Solution:
The above requirement can be addressed using two core Gang of four design pattern – Factory design pattern and Singleton design pattern. In order to generate multiple types of statements for the ATM transactions in the ATM machine we can create a Statement Factory object which will have a factory method of createStatements(). The createStatements will create DetailedStatement or MiniStatement objects. The client object will be completely unware of the object creation since it will interact with the Factory interface only. We will also create an interface called StatementType. This will allow further statement type objects e.g. Credit card statement etc to be added. So the solution is scalable and extensible following the object oriented Open/Closed design principle.
The second requirement of reducing the memory consumption can be achieved by using Singleton design pattern. The Statement Factory class need not be initiated multiple times and a single factory can create multiple statement objects. Singleton pattern will create a single instance of the StatementFactory class thus saving memory.
Problem Statement:
Design a small ATM printing application which can generate multiple types of statements of the transaction including Mini Statement, Detailed statement etc. However the customer should be aware of the creation of these statements. Ensure that the memory consumption is minimized.
Design Solution:
The above requirement can be addressed using two core Gang of four design pattern – Factory design pattern and Singleton design pattern. In order to generate multiple types of statements for the ATM transactions in the ATM machine we can create a Statement Factory object which will have a factory method of createStatements(). The createStatements will create DetailedStatement or MiniStatement objects. The client object will be completely unware of the object creation since it will interact with the Factory interface only. We will also create an interface called StatementType. This will allow further statement type objects e.g. Credit card statement etc to be added. So the solution is scalable and extensible following the object oriented Open/Closed design principle.
The second requirement of reducing the memory consumption can be achieved by using Singleton design pattern. The Statement Factory class need not be initiated multiple times and a single factory can create multiple statement objects. Singleton pattern will create a single instance of the StatementFactory class thus saving memory.
ATM example
§ Factory: Factory is an abstract class which is
a single point of contact for the client. All the concrete factory classes
needs to implement the abstract factory method.
§ StatementFactory: This is the Factory
implementation class which consist of the creator method. This class extends
from the Factory abstract class.This is the main creator class for all the
products e.g. Statements.
§ StatementType: This is a product interface
which provides abstraction to the various types of products which needs to be
created by the Factory class.
§ DetailedStatement: This is a concrete implementation
of the StatementType interface which will print the detailed statements.
§ MiniStatement: This is a concrete
implementation of the StatementType interface which will print the mini
statements.
§ Client: This is the client class which will
call the StatementFactory and StatementType and request for object creation.
Assumption:
The design solution caters to only single ATM machine.
The design solution caters to only single ATM machine.
Sample Code:
Factory.java
Code:
|
|
public abstract class Factory {
protected abstract StatementType
createStatements(String selection);
}
|
StatementFactory.java
Code:
|
|
public class StatementFactory
extends Factory {
private static
StatementFactory uniqueInstance;
private StatementFactory()
{
}
public static
StatementFactory getUniqueInstance() {
if
(uniqueInstance == null) {
uniqueInstance
= new StatementFactory();
System.out.println("Creating
a new StatementFactory instance");
}
return
uniqueInstance;
}
public StatementType
createStatements(String selection) {
if
(selection.equalsIgnoreCase("detailedStmt")) {
return
new DetailedStatement();
}
else if (selection.equalsIgnoreCase("miniStmt")) {
return
new MiniStatement();
}
throw
new IllegalArgumentException("Selection doesnot exist");
}
}
|
StatementType.java
Code:
|
|
public interface StatementType {
String
print();
}
|
DetailedStatement.java
Code:
|
|
public class DetailedStatement
implements StatementType {
@Override
public String
print() {
System.out.println("Detailed
Statement Created");
return
"detailedStmt";
}
}
|
MiniStatement.java
Code:
|
|
public class MiniStatement
implements StatementType {
@Override
public String
print() {
System.out.println("Mini
Statement Created");
return
"miniStmt";
}
}
|
Client.java
Code:
|
|
public class Client {
public static
void main(String[] args) {
System.out.println("Enter
your selection:");
BufferedReader
br = new BufferedReader(new InputStreamReader(System.in));
String
selection = null;
try
{
selection
= br.readLine();
}
catch (IOException e) {
e.printStackTrace();
}
Factory
factory = StatementFactory.getUniqueInstance();
StatementType
objStmtType = factory.createStatements(selection);
System.out.println(objStmtType.print());
}
}
|
Conclusion:
In the above articles we have gone into the
details of the Singleton pattern, how to implement singleton pattern along with
a practical application. Though singleton pattern looks a simple implementation
we should resist ourselves from using it until and unless there is a strong
requirement for it. You can blame the unpredictable nature of the results in
the multi-threading environment. Though we can use enum in
Java 5 and above it sometimes get difficult to implement your logic always in enum or
there might be legacy code before Java 5. Hope our readers have liked this
article.
Reference: Singleton Design
Pattern – An introspection and best practices from our JCG partner Mainak Goswami at the Idiotechieblog