Singleton design pattern

Singleton Design Pattern



Overview

Many times you need one and only one instance of class throughout the execution. No duplicate instances of the class. That time you should go for singleton design.

Application

The Math class is an example of Singleton Design pattern. In an application you may need only one Print spooler or Window manager. Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.
Some typical examples are Logger class, Configuration class, Accessing resources (e.g. serial port) (synchronized method), Singleton Factories

Code

There are multiple ways to implement Singleton design patterns.

1)    Throwing the exception

Create a static variable to indicate if the instance is already created or not. Throw an exception if the instance is already created. If not create the first ever instance and change the flag status.
// PrintSpooler.java
public class PrintSpooler {
       // flag to indicate if the instance is already created or not
       static Boolean instance_flag = false;
   
       // constructor to throw custom RuntimeException if the instance is already created
public PrintSpooler() throws SingletonException{
        if (instance_flag)
            throw new SingletonException("Only one instance is allowed");
        else
            instance_flag = true;
            System.out.println("Instance Created");
    }
}
// SingletonException.java
// Exception class that is used in the constructor of the Singleton class
public class SingletonException extends RuntimeException {
       public SingletonException(){
        super();
    }
   
    public SingletonException(String s){
        super(s);
    }
}

Pros

1)      With this approach if you decide to change form Singleton class to Non Singleton then it’s very easy.
2)      If one want to allow small multiple instances of the Singleton class then with very little coding one can do that.

Cons

1)      The actual code need to be wrapped in try catch block.

2)    Static classes as Singleton pattern (best example Math class)

Create a final class and all the methods as static

//Helper class
final class Helper {
       static public void method1(){
       }     
}

Pros

1)      Very simple and no need to throw exception

Cons

2)      Lot of refactoring is needed when one want to change from  Singleton class to Non Singleton

3)    Creating Singleton using  static methods (commonly used approach)

To prevent making multiple instances of the Singleton object, make the constructor itself private and instantiate it in same class’s static method
// Spooler.java
public class Spooler {
       // flag to indicate if it is singleton
       static Boolean instance_flag = false;
      
       // singleton instance variable
       static Spooler instance = null;
       // sometimes the instance is initialized right at the declaration
// static Spooler instance = new Spooler();
      
       // private constructor
       private Spooler(){};
      
       // static method to create and get the singleton instance
       // sometimes the Instance method is made synchronized so that it is thread safe
       // public static synchronized Spooler Instance() {
       public static Spooler Instance(){
              if (instance_flag )
                     return null;
              else
              {
                     instance = new Spooler();
                     instance_flag = true;
                     return instance;
              }
       }
}

Pros

1)      You don’t have to throw and catch the exception. The static method will return either new or the already created instance of the Singleton Object

Cons

Synchronization is quite expensive when it comes to performance

4)    Double locking for creating Singleton in multi-threaded env (commonly used approach)

Here the synchronized block is reduced from method to little block of code. Since you are obtaining lock on the Singleton.class, only one thread will enter the synchronized block at a time. So the first thread enters then finds Singleton and creates it and then leaves the synchronized block, then the second thread enter the block then it finds that the Singleton is not null because the first thread already created it so it will not create a new instance of Singleton
The Double checked pattern is used to avoid obtaining the lock every time the code is executed, if the call are not happening together then the first condition will fail and the code execution will not execute the locking thus saving resources.
//Lazy instantiation using double locking mechanism.
public class Singleton
{
       private static Singleton instance;

       private Singleton()
       {
       System.out.println("Singleton(): Initializing Instance");
       }

       public static Singleton getInstance()
       {
              if (instance == null)
              {
                     synchronized(Singleton.class)
                     {
                           if (instance == null)
                           {
                                  System.out.println("getInstance(): First time getInstance was invoked!");
                                  instance = new Singleton();
                           }
                     }           
              }

              return instance;
       }

       public void doSomething()
       {
              System.out.println("doSomething(): Singleton does something!");
       }
}

Pros

This is called lazy instantiation and it ensures that the singleton instance is created only when it is needed.

 

Singleton as Anti Pattern

it is overused, introduces unnecessary restrictions in situations where a sole instance of a class is not actually required, and introduces global state into an application
In short, the singleton pattern makes code more complex, less useful, and a real pain to re-use or test. Eliminating singletons can be tricky, but it’s a worthwhile endeavor.

  • Singletons frequently are used to provide a global access point for some service.
True, they do this, but at what cost? They provide a well-known point of access to some service in your application so that you don't have to pass around a reference to that service. How is that different from a global variable? (remember, globals are bad, right???) What ends up happening is that the dependencies in your design are hidden inside the code, and not visible by examining the interfaces of your classes and methods. You have to inspect the code to understand exactly what other objects your class uses. This is less clear than it could be. The urge to create something as a global to avoid passing it around is a smell in your design; it is not a feature of globals/singletons. If you examine your design more closely, you can almost always come up with a design that it is better and does not have to pass around tramp data to every object and method.
  • Singletons allow you to limit creation of your objects.
This is true, but now you are mixing two different responsibilities into the same class, which is a violation of the Single Responsibility Principle. A class should not care whether or not it is a singleton. It should be concerned with its business responsibilities only. If you want to limit the ability to instantiate some class, create a factory or builder object that encapsulates creation, and in there, limit creation as you wish. Now the responsibilities of creation are partitioned away from the responsibilities of the business entity.
  • Singletons promote tight coupling between classes
One of the underlying properties that makes code testable is that it is loosely coupled to its surroundings. This property allows you to substitute alternate implementations for collaborators during testing to achieve specific testing goals (think mock objects). Singletons tightly couple you to the exact type of the singleton object, removing the opportunity to use polymorphism to substitute an alternative. A better alternative, as discussed in the first point above, is to alter your design to allow you to pass references to objects to your classes and methods, which will reduce the coupling issues described above.
  • Singletons carry state with them that last as long as the program lasts
Persistent state is the enemy of unit testing. One of the things that makes unit testing effective is that each test has to be independent of all the others. If this is not true, then the order in which the tests run affects the outcome of the tests. This can lead to cases where tests fail when they shouldn't, and even worse, it can lead to tests that pass just because of the order in which they were run. This can hide bugs and is evil. Avoiding static variables is a good way to prevent state from being carried from test to test. Singletons, by their very nature, depend on an instance that is held in a static variable. This is an invitation for test-dependence. Avoid this by passing references to objects to your classes and methods.

No comments:

Post a Comment