What is Singleton design pattern?
In a previous blog post, I introduced Builder design pattern. Today, let’s learn another design pattern: Singleton. Both Singleton and Builder are considered Creational design patterns. There are typically 3 types of design pattern: Creational design pattern, Structural design pattern and Behaviour design pattern. Creational design patterns are all about class instantiation. For example, Builder design pattern benefits the instantiation of a complicated class with multiple parameters where some of them are even optional.
Singleton design pattern benefits the instantiation of a class which can be used over and over again. It makes sure a class only has one object and provide a global point of access to it. One use case is Logger class. To log the application, Logger instance is injected to multiple classes that need logging. Singleton design pattern can provent us creating multiple instances of the Logger class. Instead, we create only one Logger instance and use it where it is needed. Clearly, one advantage of Singleton design pattern is to save memory and avoid creating unnecessary mutilple instances.
Implementation in Java
To implement Singleton design pattern in Java, here are 2 ways: Eager and Lazy. Both end up with creating one single instance for a class.
Eager instantiation
The first implementation is eager instantiation, where instance is always created during class loading.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class SingletonEager {
// Create an instance
private static final SingletonEager INSTANCE = new SingletonEager();
// Make constructor private, so it cannot be instantiated from outside class
private SingletonEager() {}
// Create a static getInstance method
public static SingletonEager getInstance() {
return INSTANCE;
}
public void printOK() {
System.out.println("OK!");
}
}
Then we can access the Singleton instance by
1
SingletonEager singletonEager = SingletonEager.getInstance();
This method is easy to implement. However, one concern of using this method is resource wastage, because the instance is always created, whether it is required or not.
Lazy instantiation
The second implementation is lazy instantiation, where instance is created only when it is called.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SingletonLazy {
// Declare a static instance
private static SingletonLazy INSTANCE;
// Make constructor private, so it cannot be instantiated from outside class
private SingletonLazy() {}
// Create a static getInstance method
public static SingletonLazy getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingletonLazy();
}
return INSTANCE;
}
public void printOK() {
System.out.println("OK!");
}
}
This method can avoid resource wastage, because the instance is only created when getInstance
is called. However, this method is workable in single-thread situation. This causes a problem in multi-thread situation where INSTANCE
happens to be created in more than one thread in the same time.
To fix this problem, we can use synchronized
keyword to make this creation operation atomic. But it potentially impact the performance by increasing waiting time of threads.
1
2
3
4
5
6
public synchronized static SingletonLazy getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingletonLazy();
}
return INSTANCE;
}
Conclusion
Based on pros and cons listed above, you can choose which one is better for your use case.
Comments powered by Disqus.