Tuesday 9 April 2013

Singleton Design Pattern V/S Static Classes

Singleton Design Pattern 

Singleton is known as a creational pattern and it is the most commonly used design patterns. It governs the Instantiation process. It proposes that at any point of time there can only be one instance of a singleton (object) created by the JVM. As per GOF (Gang of Four) book: - Ensure a class has only one instance and provide a global point of access to it.


Difference between Singleton and Static Class

  1. Singleton object stores in Heap but, static object stores in stack. 
  2. We can clone the object of Singleton but, we cannot clone the static class object.
  3. Static classes are much faster than Singleton because static methods are bonded at compile time.
  4. It is hard to mock Static classes and difficult to write Junit test cases but on the other hand it is easier to mock Singleton classes so easy to write Junit test cases  because we can pass mock object whenever Singleton is expected, e.g. into constructor or as method arguments.
     5.  If we need to maintain state then Singleton pattern is the best choice or if we need to provide only global access to methods and no need to maintain state then we can go with Static classes.
     6.  Static classes are always eagerly loaded while Singleton classes can be lazy loaded if their object is not a light weight object. 
     7.  We can also consider using static method, if we need to combine group of utility methods all together.
       


Note: - It is not advised to maintain state inside static class, especially in concurrent environment, where it could lead to race conditionswhen modified parallel by multiple threads without proper synchronization.
Uses of Singleton Design Pattern: - Singletons can be used to create a Connection Pool. Singleton patterns are used in logging, caches, thread pools, configuration settings, device driver objects. java.lang.Runtime. and java.awt.Desktop. is the example of Singleton Design pattern where as java.lang.Math is the best example of static classes.

How to Implement Singleton Pattern in Java 

To implement Singleton Design pattern, we need to go through the below conditions.
  • Private constructor to restrict instantiation of the class from other classes.
  • Private static variable of the same class that is the only instance of current class.
  • Public static method that returns the instance of the class, this is the global access point for outer world to get the instance of the singleton class.
  • If want to access in multithreading programming then better to use synchronized keyword with the Public static method.
  • If we want that Singleton Class can’t be sub classed by other then we can go with final singleton class.
  • If we want that nobody can create another instance of this singleton class using Reflection as we can access private members of any class using Reflection then we can throw exception inside the private constructor.
  • If we want to restrict not to create another instance of singleton class using clone() method then we have to override the clone() method.
  • If we are using serializable implementation on Singleton class in order to use in distributed systems so that we can store it’s state in file system and retrieve it at later point of time. So whenever we will deserialize, it will create a new instance of the class. To overcome from this problem we have to provide the implementation of readResolve().

Singleton Design Pattern Example by following the above rules

package com.gaurav.javaprograms;

import java.io.Serializable;

public final class ActualSingletonDemo implements Serializable {

    /**
     * Added a serial version id, Reason - Suppose our class structure is changed after
     * serialization then when we will try to de-serialize, it will through
     * InvalidClassException. So it will be good to declare a serialVersionUID.
     *
     */
    private static final long serialVersionUID = 3119105548371608200L;

    private String name = "GAURAV";

    /**
     * Volatile keyword in Java is used as an indicator to Thread that do not cache value of this variable and always read it from
     * main memory. If a variable is not shared between multiple threads no need to use volatile keyword with that variable.
     * Another effect is the use of memory that is local to a thread, so that changes aren't immediately visible to all other threads.
     * The consequence is that other threads can see inconsistent states. volatile keyword is a kind of tool to control these effects.
     */
   
    private static volatile ActualSingletonDemo singleton = null;

    /**
     * IllegalStateException is thrown in order to prevent from instance
     * creation Using reflection, as private members can be accessed Using
     * reflection.
     */
    private ActualSingletonDemo() {
        if (singleton != null) {
            throw new IllegalStateException(
                    "Singleton instance already created");
        }

    }

    /**
     * ************* Single Check for instance creation ****************
     * public static ActualSingletonDemo getInstance()
     * {
     *     if (singleton == null)
     *     {
     *         synchronized (ActualSingletonDemo.class)
     *             {
     *             singleton = new ActualSingletonDemo();
     *             }
     *         }
     *         return singleton;
     *     }
     */

    /**
     * In the above Single Checking for instance creation, Assume there are two
     * threads Thread1 and Thread2. Both will come to create instance and
     * execute "singleton==null", now both threads have identified instance
     * variable to null thus assume they must created an instance. They
     * sequentially goes to synchronized block and create the instances. At the
     * end, we have two instances in our application. This error can be solved
     * using double-checked locking. This principle tells us to recheck the
     * instance variable again in synchronized block in the given below way:
     */
    public static ActualSingletonDemo getInstance() {
        if (singleton == null) {
            synchronized (ActualSingletonDemo.class) {
                // Double check
                if (singleton == null) {
                    singleton = new ActualSingletonDemo();
                }
            }
        }
        return singleton;
    }

    /**
     * Preventing of another instance creation using clone() method. Suppose I
     * am not overriding clone method here. Then we can't create clone of this
     * class. Suppose my singleton class is extending a class which is
     * supporting cloning then using clone we can create an another instance of
     * this class, then the singleton rule is violated. So it's necessary to
     * override this clone() method.
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException(
                "Cloning for this class is not allowed");
    }

    /**
     * This will help not to create another instance when we will try to
     * de-serialize the class. Because for distributed application it is
     * frequently required to serialize the objects in file system, only to read
     * them later whenever required. Note:- de-serialization always creates a
     * new instance. So it's better approach to include the readResolve() method
     * in this class. This method will be invoked when we will de-serialize the
     * object. Inside this method, we must return the existing instance to
     * ensure single instance through out the application.
     */
    protected Object readResolve() {
        return singleton;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}


Now We will create sample programs to access the ActualSingletonDemo class and will try to create more than one instance using clone(), Reflection and De-Serialization techniques.

Sample for trying to create more than one instance Using Clone() Method:-

package com.gaurav.javaprograms;

public class ActualSingletonAccessUsingClone {
    public static void main(String args[]) throws Exception {
       
        ActualSingletonDemo obj = ActualSingletonDemo.getInstance();
        System.out.println("The first instance object is-"+obj);
       
        ActualSingletonDemo clone = (ActualSingletonDemo) obj.clone();
        System.out.println("The clone instance object is-"+clone);
    }
}

Result :-

 

Note:-  As in the ActualSingletonDemo class, We have overrided the clone method where we are throwing CloneNotSupportedException. So the above result proves that we are not able to create another instance using clone().


Sample program for trying to create more than one instance Using Reflection Method:-

package com.gaurav.javaprograms;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ActualSingletonAccessUsingReflection {
    public static void main(String[] args) throws InvocationTargetException {
        try {
            System.out
                    .println("Inside main() - Getting the first singleton instance using getInstance() method...");
            ActualSingletonDemo asd = ActualSingletonDemo.getInstance();
            System.out.println("The first instance is-" + asd);
            System.out
                    .println("Inside main() - Trying to use reflection to get another instance...");
            Class<ActualSingletonDemo> clazz = ActualSingletonDemo.class;
            Constructor<ActualSingletonDemo> cons = clazz
                    .getDeclaredConstructor();
            cons.setAccessible(true);
            ActualSingletonDemo asd2 = cons.newInstance();
            System.out.println("The another instance is-" + asd2);
        } catch (SecurityException se) {
            se.getMessage();
        } catch (NoSuchMethodException nsme) {
            nsme.getMessage();
        } catch (IllegalArgumentException iae) {
            iae.getMessage();
        } catch (InstantiationException ie) {
            ie.getMessage();
        } catch (IllegalAccessException iae) {
            iae.getMessage();
        }
    }
}


Result : -



Note:- As in the ActualSingletonDemo class, we are throwing IllegalStateException, in the private constructor, So the above result is proving that using reflection also we are not able to create more then one instance of this class.


 Sample program for trying to create more than one instance Using De-Serialization Method:-

package com.gaurav.javaprograms;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class ActualSingletonAccessUsingSerialize {
    static ActualSingletonDemo singletonOne = ActualSingletonDemo.getInstance();

    public static void main(String[] args) {
        try {
            // Serialize to a file
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
                    "D:\\actualSingletonDemo.ser"));
            out.writeObject(singletonOne);
            out.close();

            singletonOne.setName("KUMAR");

            // DeSerialize from a file
            ObjectInput in = new ObjectInputStream(new FileInputStream(
                    "actualSingletonDemo.ser"));
            ActualSingletonDemo singletonTwo = (ActualSingletonDemo) in
                    .readObject();
            in.close();

            System.out.println(singletonOne.getName());
            System.out.println(singletonTwo.getName());

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


Result : - 
          
          
                                                     Result Without readResolve() method


Result With readResolve() method

Note :- As we know de-serialization always creates a new instance, but after including the readResolve() method the above output proves that using serialization also we are not able to create another instance of the class ActualSingletonDemo.



Singleton Using Enum



Java API ensures that any Enum value is instantiated only once in a Java program. Since Java Enum values are globally accessible, so it is singleton. Enum  provides implicit support for thread safety and only one instance is guaranteed. Enum instances are by default final in Java, it also provides safety against multiple instances due to serialization. Serialization guarantees by JVM and Enum also helps to reduce amount of code. This is also a good way to have singleton with minimum effort. Only drawback is that it does not allow lazy initialization.

Sample Example Using Enum

package com.gaurav.javaprograms;

public enum SingletonUsingEnum {
    INSTANCE;
   
    private int age = 30;
   
    public int getAge(){
        return age;
    }
    public void accessibleFunction(String param) {
        System.out.println("The passed string parameter value is-"+param);
    }
   
}

No comments:

Post a Comment