Singleton Pattern
- It comes under creational pattern as this pattern provides one of the best ways to create an object.
- This pattern involves a single class which is responsible to create an object while making sure that only single object gets created. This class provides a way to access its only object which can be accessed directly without need to instantiate the object of the class.
Applicability:
- Use the Singleton pattern when a class in your program should have just a single instance available to all clients; for example, a single database object shared by different parts of the program.
- Use the Singleton pattern when you need stricter control over global variables.
- For accessing cache-memory, database connection, drivers, logging. etc.
Pros and Cons
Pros | Cons |
---|---|
control access to shared resources (databases; files etc) | tight coupling -> complication for scaling and testing |
global access point for singletoned instances | static memory allocation |
one time initialization | hidden dependencies in the code |
ensuring maximum number of instances per object | violation of single responsibility principle |
complications in multithreaded solutions |
Class Diagram
Issues with Singleton Testing
- Singleton is not testable because:
- As the singleton object acts as a global variable in the program, the change in state of the singleton object will affect the state of the whole program.
- While two or many objects in the program tries to mutate the state of the program, it may enter the race condition.
- The unit tests are independent of each other, but with the singleton object, the tests are not independent, because they depend on the singleton object.
- Singleton is not thread-safe.
- Singleton is not mockable.
Implementation
Step 1
Create a Singleton Class.
SingleObject.java
public class SingleObject {
//create an object of SingleObject
private static SingleObject instance = new SingleObject();
//make the constructor private so that this class cannot be
//instantiated
private SingleObject(){}
//Get the only object available
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
Step 2
Get the only object from the singleton class.
SingletonPatternDemo.java
public class SingletonPatternDemo {
public static void main(String[] args) {
//illegal construct
//Compile Time Error: The constructor SingleObject() is not visible
//SingleObject object = new SingleObject();
//Get the only object available
SingleObject object = SingleObject.getInstance();
//show the message
object.showMessage();
}
}
Output
Hello World!
Example:
Counter
Counter.java
public class Counter {
//create an object of Counter
private static Counter instance = new Counter();
private static int count = 1;
//make the constructor private so that this class cannot be
//instantiated
private Counter(){}
//Get the only object available
public static Counter getInstance(){
return instance;
}
public void increment(){
count++;
}
public void decrement(){
count--;
}
public void showCount(){
System.out.println("Count: " + count);
}
}
SingleCounterDemo.java
public class SingleCounterDemo {
public static void main(String[] args) {
//create an object of Counter
Counter counter_one = Counter.getInstance();
Counter counter_two = Counter.getInstance();
// Display both counts
counter_one.showCount();
counter_two.showCount();
// Increment counter one.
counter_one.increment();
// Display both counts
counter_one.showCount();
counter_two.showCount();
// Increment counter two.
counter_two.increment();
// Display both counts
counter_one.showCount();
counter_two.showCount();
}
}
Output
Count: 1
Count: 1
Count: 2
Count: 2
Count: 3
Count: 3
Database Connection
JDBCSingleton.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DatabaseConnection {
private static Connection con = null;
static
{
String url = "jdbc:mysql:// localhost:3306/org";
String user = "root";
String pass = "root";
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url, user, pass);
}
catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
public static Connection getConnection()
{
return con;
}
}