Java- Understanding of Sigleton Design Pattern - JavaTechWorld

Thursday, 2 February 2017

Java- Understanding of Sigleton Design Pattern

Singleton Design Pattern in java ensure that class has only one instance and provide global access to it that means across your application you are going to have only one instance of the class and whenever you need it you are not going to create it using new Keyword.

Implementation of Singleton Class –
  • Make Sure there is only one instance.
  • Make consutructor as private and let the class manage its instance.
  • Provide global point of access.
Example –

package singleton;
public Class MySingleton {
private static MySingleton instance=new MySingleton();
private MySingleton() {
System.out.println(“User can’t create object using new keyword”);
}
public static MySingleton getInstance() {
return instance;
}
//How to use Singleton class
Class TestClass {
public static void main(String[] args) {
MySingleton ms=new MySingleton(); // Not allowed
MySingleton ms1=MySingleton.getInstance();
MySingleton ms2=MySingleton.getInstance();
print(“MySingleton”+ms1);
print(“MySingleton”+ms2);
}
static void print(String name, MySingleton object) {
System.out.println(String.format(“Object : Hashcode”, name, object.hashcode()));
}
}
if i will run this TestClass then constructor will be called because class is initialized during class loading then i got two instances ms1 and ms2 and printed them and we will get same Hascode but this singleton class have some issue which we are going to discuss.
In this singleton class we are violating the requirement of singleton class using the following point.
  1. Reflection
  2. Seriallization/deserialization
  3. clone
  4. multi-threaded access
  • Reflection– Reflection allows you to construct singleton a object without using new instance or any other api.
Example

package singleton;
public Class MySingleton {
private static MySingleton instance=new MySingleton();
private MySingleton() {
System.out.println(“User can’t create object using new keyword”);
}
public static MySingleton getInstance() {
return instance;
}
//How to use Singleton class
Class TestClass {
public static void main(String[] args) throws Exception{
MySingleton ms=new MySingleton(); // Not allowed
MySingleton ms1=MySingleton.getInstance();
MySingleton ms2=MySingleton.getInstance();
print(“MySingleton”+ms1);
print(“MySingleton”+ms2);
//Reflection
Class cls=Class.forName(“singleton.MySingleton”); //This way i am going to load a class
//Using this cls i am going to get default constructor.
Constructor<MySingleton> ctr=cls.getDeclaredConstructor(); // I got the default constructor now it is private i can’t invoke it, so i am going to use setAccessible api. By using this i am changing constructor to public constructor.
ctr.setAccessible(true);
MySingleton ms3=ctr.newInstance();
print(“MySingleton ms3”,ms3);
}
static void print(String name, MySingleton object) {
System.out.println(String.format(“Object : Hashcode”, name, object.hashcode()));
}
}
if we run TestClass hascode for ms3 will be different that means we have successfully violated the singleton requirement.
  • Serialization/deserialization – Serialization is a process of writing object data into a stream and late you can read it back and construct your object back by deserialization. Now Let’s see the example.
Example –
package singleton;
public Class MySingleton implements Serializable {
private static MySingleton instance=new MySingleton();
private MySingleton() {
System.out.println(“User can’t create object using new keyword”);
}
public static MySingleton getInstance() {
return instance;
}
//How to use Singleton class
Class TestClass {
public static void main(String[] args) {
MySingleton ms=new MySingleton(); // Not allowed
MySingleton ms1=MySingleton.getInstance();
MySingleton ms2=MySingleton.getInstance();
print(“MySingleton”+ms1);
print(“MySingleton”+ms2);
//Serialization example
ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream(“xyz.ser”));
oos.writeObject(ms1);
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(“xyz.ser”));
MySingleton ms3=(MySingleton)ois.readObject();
print(“MySingleton”+ms3);
}
static void print(String name, MySingleton object) {
System.out.println(String.format(“Object : Hashcode”, name, object.hashcode()));
}
}
In this TestClass i am serializing ms1 object and then i have deserialized it and i am trying to print ms3 object hashcode and the hascode is different.


  • Clone – Cloning is the another way of violating the singleton definition. For this i am going to implement Cloneable interface. whenever i am implementing cloneable interface i am able to override clone() method which by default calls super.clone() api. Now i am trying to clone ms2 object (refer the TestClass). if i will print ms3 the hashcode will be different which violate singleton rule.
Example –
package singleton;
public Class MySingleton implements Cloneable {
private static MySingleton instance=new MySingleton();
private MySingleton() {
System.out.println(“User can’t create object using new keyword”);
}
@Override
protected object clone() throws CloneNotSupportedException {
return super.clone();
}
public static MySingleton getInstance() {
return instance;
}
//How to use Singleton class
Class TestClass {
public static void main(String[] args) {
MySingleton ms=new MySingleton(); // Not allowed
MySingleton ms1=MySingleton.getInstance();
MySingleton ms2=MySingleton.getInstance();
print(“MySingleton”+ms1);
print(“MySingleton”+ms2);
//Cloneable example
MySingleton ms3=(MySingleton) ms2.clone();
print(“MySingleton”,ms3);
}
static void print(String name, MySingleton object) {
System.out.println(String.format(“Object : Hashcode”, name, object.hashcode()));
}
}
  • Multi-threaded access – This is another way of violate the singleton rule. This is most important scenario because when multiple thread are trying to create your singleton. So in our example we have eagerly created the instance here but this is always not a very good practice sometimes you don’t need instance until the getInstance() is called you don’t really need to construct a MySingelton object. In this case you would delay the creation of MySingleton until it is mandatory. Other advantage to creating an instance of MySingleton is suppose at the time of class loading instance creation is failed so we don’t have chance again to recreate that instance until you reload the class. That is why we have declared static instance variable as null and creating instance lazily in the getInstance() method. So in the getInstance() method we will check if instance is null we are going to create instance of our singleton class.
Example –
package singleton;
public Class MySingleton {
//private static MySingleton instance=new MySingleton();  //eagerly created instance.
private static MySingleton instance=null;
private MySingleton() {
System.out.println(“User can’t create object using new keyword”);
}
public static MySingleton getInstance() {
if(instance==null) {
instance=new MySingleton();
return instance;
}
//How to use Singleton class
Class TestClass {
public static void main(String[] args) {
MySingleton ms=new MySingleton(); // Not allowed
MySingleton ms1=MySingleton.getInstance();
MySingleton ms2=MySingleton.getInstance();
print(“MySingleton”+ms1);
print(“MySingleton”+ms2);
MySingleton ms3=MySingleton.getInstance();
print(“MySingleton”,ms3);
}
static void print(String name, MySingleton object) {
System.out.println(String.format(“Object : Hashcode”, name, object.hashcode()));
}
}

© 2014 JavaTechWorld. Designed by Bloggertheme9
Powered by Blogger.