Singleton Design Pattern
The Singleton Design Pattern in java restricts the instantiation of a class to a “single” object. It is a creational pattern as it deals with object creation. Also, this pattern is the simplest among all design patterns.
A java class is following singleton pattern if the following statements are true.
- The class must have only one instance.
- The class provides global access to that instance.
- Other components cannot create objects on their own for the class
Implementation
To implement a singleton pattern in java, you need to follow the below steps.
- Create a single instance within the class.
- Provide a static method to return the reference to that instance.
- Declare all constructors as “private” so that other components cannot create objects for this class.
Explanation
Let’s break this code down bit by bit. The INSTANCE
is the singleton object here. It is defined with private, static and final keywords. Because, this object should not be accessible outside, It should initialize at the class level and it should not be changed in future.
The constructor is private so that other classes cannot use them to create an object of Singleton class.
Finally the getInstance method is public
so that other classes can call this method. It is also static
so that the calling classes doesn’t require an object to call this method.
Variations of Singleton Design pattern in Java
For performance reasons, there are different ways to implement a Singleton in java. Let’s go through each of them with an example.
Eager initialization
In this approach, the singleton object is pre-initialized when the class is created. This might be a good thing for smaller objects. However, initializing large objects may inflate the startup times.
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Code language: Java (java)
As you see in the highlighted line, the object initializes when the class loads.
Lazy Initialization
Being opposite to Eager initialization, The class will create the singleton object only when another class requires it. After that, the same object will be returned for future requests.
public final class LazySingleton {
private static LazySingleton INSTANCE;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new LazySingleton();
}
return INSTANCE;
}
}
Code language: Java (java)
In this case, We are not initializing INSTANCE
beforehand. Instead, we only initialize it on the first call to getInstance method. There are few drawbacks when we use this approach in a multi-threaded environment.
Singleton Pattern with Multi Threading
With the lazy initialization approach, two or more threads may initialize the object. But this is strictly against the singleton design pattern as there should only be one object. So we should make sure multi threaded environments are handled well. One way to do that is to add synchronized keyword to the getInstance() method.
public final class SynchronizedSingleton {
private static SynchronizedSingleton INSTANCE;
private SynchronizedSingleton() {
}
public static synchronized SynchronizedSingleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new SynchronizedSingleton();
}
return INSTANCE;
}
}
Code language: Java (java)
You could also handle this situation with the help of synchronized blocks.
public static SynchronizedSingleton sayHello() {
synchronized(SynchronizedSingleton.class){
if (INSTANCE == null) {
INSTANCE = new SynchronizedSingleton();
}
}
return INSTANCE;
}
Code language: Java (java)
By using synchronized keyword, only one thread get to use the method/block at the same time.
Accessing Singleton objects
As we know how to write a getInstance method, let’s see how to access the singleton object’s methods. Let’s say The singleton class has a method called sayHello()
. As the getInstance method returns an object, it is easier for us to access these methods. For example, take a look at this main class.
public class SingletonTest {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
instance.sayHello();
}
}
Code language: JavaScript (javascript)
This snippet results in the following output.
And that’s how you access singleton objects in java classes.
Disadvantages of Singleton Pattern
Like many concepts and tools, Singleton pattern cannot solve all the problems. There are a couple of situations where singleton pattern is bad.
Difficult to unit test
Singleton pattern makes unit testing difficult. As singletons carry the state globally, One unit test may affect the setup of another. This nature makes Singletons a pain when it comes to testing classes that involves with Singletons. If you need to work with singletons in test cases, then
- You must take care of the order in which the test cases run.
- Test cases cannot run in parallel. Thus leading to longer time for test case execution.
- The test cases involving Singletons would cause side effects on other test cases.
- Consistent results are not guaranteed with Singletons due to side effects.
- Faking a Singleton is Hard.
Singleton and Classloaders
Singleton objects are created at class loading time. So the application can have more than one singleton object if it have more than one class loader. For example,The tomcat has a hierarchy of class loaders. If each of them get to load the singleton class, then technically you have more than one singleton object. Which is a bad thing.
Reflections break Singleton Pattern
Singleton may restrict object creation by hiding constructors. But you could still create a singleton using Java Reflections. For example, you could mark the constructor as accessible through reflection.
Class singletonClass= Singleton.class;
Constructor constructor = singletonClass.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton newSingletonObject= constructor.newInstance();
Code language: JavaScript (javascript)
You can fight back on this approach by adding a check in your constructor.
private Singleton() {
if (INSTANCE != null) {
throw new IllegalStateException("Instance already created!");
}
}
Code language: PHP (php)
Singleton Pattern is an Anti Pattern
Even though Singleton solves many design problems, from OOP perspective, it is a bad design pattern. And here is why.
- Singleton classes are hard to extend (No inheritance)
- No way of knowing if the object is a new or old instance.
- Singleton classes are bad for dependency injection. Even if we could inject through properties, it would cause side effect on all places.
Summary
To sum it up, We learned what is Singleton Design pattern, How to implement on in various ways and how to use a singleton pattern. Also we learn when not to use Singleton pattern and
You can find all of these samples at our github repository.