Singleton Design Pattern

Introduction

The Singleton is a creational design pattern that ensures that a class has only one instance throughout the application. This instance is accessible from any part of the application with global access.

Why do we need a single instance of some object?

There might be some object which is common to all parts of the program and we require a single instance of it. For example, consider a cost estimation system of an organization that estimates the overall expenditure of the organization. The organization has several departments working together and contributing different costs for their tasks. Still, all the departments report their respective expenditure to a single-common object of the cost estimator system. Here object to which all departments report should have global access so that all departments can access it. 

Note: There can be some exceptional situations where the object does not require a global access level i.e. some departments might not need the object of the cost estimator system. For the rest of the discussion, we’ll consider scenarios in which an object of a singleton class requires a global access level.

Understanding Singleton via an Example!

Let’s take the example of the cost estimating system. Our goal would be to create a system for a hypothetical company “COMPANY” with two different departments: writing and publishing departments. Each of these departments adds some amount to the company’s expenditure cost and we want to estimate the total cost from the beginning until the present date. For this, we will keep track of the cost in an instance of CostEstimatorclass.

There are two major points to focus on:

  • We have to make sure that there is only one instance of CostEstimator so that all the departments report to a single object in the entire lifetime of the program.
  • This object must be available to each department.

Solution Approach 1

The first thing that might come to anyone’s mind is to declare an instance of CostEstimator class as a global object so that it is accessible to all departments.

public class CostEstimator{
    public CostEstimator() {
        //constructor
    }
    //rest part of the class
}
CostEstimator globalcost = new CostEstimator();
//declared in global scope

void department1 () {
    //uses globalcost
}
void department2 () {
    //uses globalcost
}

Key Observations

This approach doesn’t ensure that there will be only one instance of CostEstimator. There can be a part of code that calls the constructor of CostEstimator to create a new instance of the same. Note: constructor of any class always returns a new instance of that class.

Consider the following example code where department1() may create a new instance of CostEstimator class, which is not desirable. So, this approach doesn’t fulfill our requirement of only one instance.

//...
void department1 () {
    //uses globalcost
    //creates a new CostEstimator instance
    CostEstimator newcost = new CostEstimator();
}
void department2 () {
    //uses globalcost
}
//...

Efficient Approach using the Singleton Pattern

Now our goal would be to make the CostEstimator class itself responsible for keeping track of its single instance to ensure that no more than one instance is created. If the client creates a new instance, the CostEstimator class should abort that request and return the existing single instance. Moreover, the class must provide a way to access its single instance. Let’s see how to do it!

If the client can directly make a call to the constructor of CostEstimator class, then it’ll create new instances anytime. Therefore, we must make the constructor private to ensure that no one can directly call the constructor of CostEstimator. In other words, we’ve made the constructor private, due to which no one out of the CostEstimator class can instantiate its new instance.

To keep track of its single instance, we will declare a static member Cost of the same type as the class CostEstimator. We will also create a static method getCost() to instantiate and return the single instance of the class CostEstimator. If the object of the static member Cost already exists (that is, has been instantiated once), it will return that instance. Otherwise, it’ll instantiate the new instance of the static class Costvia the private constructor and return it.

Key Observations

  • We’ve restricted the constructor call to the class only by declaring it as private. So there won't be multiple instances of the CostEstimator class. In other words, the CostEstimator class will be the Singleton class.
  • By declaring the getCost() and Cost as static, we ensure that any object of CostEstimator will always refer to the same instance stored in the member Cost. Therefore, only one instance of CostEstimator will exist in the entire program.

So this approach uses the Singleton pattern, which overcomes the drawbacks of the previous approaches to a great extent.

What is the meaning of singleton design pattern?

Implementation Idea: Component and Structure

How does singleton pattern work?

  • Singleton (CostEstimator): It containsa static member(Instance) of the same type as that of the class to store the single instance of the class and a static method GetInstance() that lets clients access its unique instance.
  • Client (COMPANY): The part of code which uses the Singleton.

What is singleton design pattern with example?

Implementation of the CostEstimator Class

This is a singleton class that estimates the total amount spent using the public method addAmount(int amount) and returns the calculated amount using the method showAmount().

In this class, we create a static method getCost() that allows the clients to access the single instance stored in a static member Cost. We also need to add the core logic of the CostEstimator class (obviously, the CostEstimator class must have some work to do other than creating its sole instance).

public static class CostEstimator {
    private int amount;
    private static CostEstimator Cost = null;
    private CostEstimator () {
        this.amount = 0;
    }
    public static CostEstimator getCost () {
        if(Cost == null) {
           Cost = new CostEstimator();
        }
        //Notice that we've implemented lazy initialization
        return Cost;
    }
    public int showAmount () {
        return amount;
    }
    public void addAmount(int amount){
        this.amount = this.amount + amount;
    }
}

Implementation of the COMPANY Class

This is a client class with an instance of CostEstimator which updates and displays the amount contained in the single instance of CostEstimator.

public static class COMPANY {
        
    private CostEstimator costestimator;
        
    public COMPANY (CostEstimator costestimator) {
           
        this.costestimator = costestimator.GetCost();
        //We have to use GetCost() method in order to use the single instance
    }    
        
    public void Writing (int amountWriting) {
        System.out.println ("Writing... \n Current Total Cost");
        costestimator.AddAmount(amountWriting);
        System.out.println (costestimator.ShowAmount()); 
    }
        
    public void Publishing (int amountPublishing) {
        System.out.println ("Publishing... \n Current Total Cost - ");
        costestimator.AddAmount(amountPublishing); 
        System.out.println (costestimator.ShowAmount());
    }
}
    
public static void main(String []args) {
        
    //initializing the sole instance
    CostEstimator costestimator = CostEstimator.GetCost();
        
    COMPANY company = new COMPANY (costestimator);
        
    Scanner sc = new Scanner (System.in);
    System.out.println("Enter cost of Writing: \n");
    int amountWriting = sc.nextInt();
    //adding writing cost
    company.Writing(amountWriting);
        
        
    System.out.println("Enter cost of Publishing: \n");
    int amountPublishing = sc.nextInt();
    //adding publishing cost
    company.Publishing(amountPublishing);
}

Note: It is necessary to declare the Cost member as a static member because we want a single instance of the class. And to access this static member, we need to declare GetCost() as a static method. Further, we’ve two choices for initialization of the Cost member, namely:

  • Lazy initialization: The object isn’t created until it’s needed for the first time. (In the above code, we’ve followed lazy initialization)
  • Early initialization: The object is initialized at the time of declaration itself. Only some part of the CostEstimator class will be changed: 
public static class CostEstimator {
    private int amount;
    private static CostEstimator Cost = new CostEstimator();
    private CostEstimator () {
        this.amount=0;
    }
        
    public static CostEstimator GetCost () {
        return Cost;
    }
        
    public int ShowAmount () {
        return amount;
    }
}

When to apply Singleton Pattern

We should use the Singleton pattern when

  • Only a single instance of the class should exist and must be accessible to other classes from a well-known access point (easily accessible).

Consequences

  • We gain more control over the sole instance by encapsulating it in the Singleton(CostEstimator) class.
  • We can gain a global access point for the sole instance.
  • It violates the Single Responsibility Principle as the Singleton class is responsible for maintaining its sole instance(and providing global access), and it is also responsible for the main role of the class (known as the “business logic”). For instance, in our example of CostEstimator, the business logic was to show the cost.
  • Subclassing a singleton might be tricky because it has a private constructor. We need to change the private constructor to a public one, but it does not remain Singleton anymore. Even if we change the constructor of the Singleton class from private to public, the implementation of Singleton will contain static members who will be automatically shared with the subclasses, which is usually not desirable.

Used in

Some prominent uses of the singleton pattern can be found

Conclusion

In this blog, we’ve seen the scenarios where one has to use a single instance of a class only along with a global access level. The singleton creational design pattern helps in accomplishing these scenarios. Then, we explored the Singleton design pattern with different initialization modes (early and lazy). Finally, we saw some of its applicabilities and effect on the entire creational process.

Further Exploration

  • Try to increase the number of permissible instances (e.g., up to 4 instances) by changing the getInstance() method and Singleton class.
  • Try to implement other creational patterns, such as abstract factory builder patterns, with the help of a singleton pattern.

Enjoy learning, Enjoy oops!

More From EnjoyAlgorithms

Our weekly newsletter

Subscribe to get free weekly content on data structure and algorithms, machine learning, system design, oops design and mathematics.

Follow Us:

LinkedinMedium

© 2020 EnjoyAlgorithms Inc.

All rights reserved.