Singleton Explained

There are handful of ways to define a Singleton class in Java. They aren’t that difficult yet, doing it the correct way matters. Here I have listed 3 ways of doing it. However, only the 3rd which uses on-demand holder acronym is preferred as the singleton instance created here is thread-safe & is unique.

Trivia 1: Why we don’t import classes like System, Integer and String?
Ans: The package java.lang.*; is implicitly imported.

Trivia 2: Can main method of a java program reside in an abstract class?
Ans: Yes it can! See the Driver class below.

1. Eager Singleton

package design.com.hamzeen;

public class EagerSingleton {
	private static EagerSingleton ins = new EagerSingleton();

	public static EagerSingleton getInstance() {
		return ins;
	}

	private EagerSingleton() {
	}
}

2. Lazy Singleton

package design.com.hamzeen;

public class LazySingleton {
	private static LazySingleton ins;

	public static LazySingleton getInstance() {
		if (ins == null) {
			ins = new LazySingleton();
		}
		return ins;
	}

	private LazySingleton() {
	}
}

3. Singleton Holder

package design.com.hamzeen;

public class SingletonHolder {
	public static SingletonHolder getInstance() {
		return Holder.ins;
	}

	private static final class Holder {
	  private static final SingletonHolder ins = 
				new SingletonHolder();
	}

	private SingletonHolder() {
	}
}

The Driver and Output

package design.com.hamzeen;

public abstract class Driver {

	public static void main(String[] args) {
	  EagerSingleton a1 = EagerSingleton.getInstance();
	  EagerSingleton a2 = EagerSingleton.getInstance();
	  System.out.println(a1.toString());
	  System.out.println(a2.toString());

	  LazySingleton b1 = LazySingleton.getInstance();
	  LazySingleton b2 = LazySingleton.getInstance();
	  System.out.println(b1.toString());
	  System.out.println(b2.toString());

	  SingletonHolder c1 = SingletonHolder.getInstance();
	  SingletonHolder c2 = SingletonHolder.getInstance();
	  System.out.println(c1.toString());
	  System.out.println(c2.toString());
	}
}

design.com.hamzeen.EagerSingleton@15db9742
design.com.hamzeen.EagerSingleton@15db9742
design.com.hamzeen.LazySingleton@6d06d69c
design.com.hamzeen.LazySingleton@6d06d69c
design.com.hamzeen.SingletonHolder@7852e922
design.com.hamzeen.SingletonHolder@7852e922
Advertisements

An insight into observer pattern

One of the things which I often encounter these days is design patterns. If I’m to give a head first to design patterns, they articulate solutions to some of the commonly occurring design problems with related to software development. Hence, it promotes design reusability just as Object-Oriented Programming (OOP) encourages code reusability. The Observer, which is classified as a behavioral pattern can become quite handy in case of handling events (event-driven) specially, if your project adopts Model View Control (MVC) architecture.

At the heart of Observer pattern are Source and its Observers. The idea behind the pattern is to allow multiple observers (which can be views such as windows, web pages or any other simple UI element like a label) to be able to listen to its Model, known as the Source by registering to it. The relationship between the source and the observers is hence, known as publish-subscribe relationship.

An apt situation to employ Observer would be, modifying a certain field on a window while couple of more windows which also utilize the same field are kept opened. One would expect this modification to instantaneously take effect on all of the windows which utilize the particular field. This characteristic can easily be ensured with Observer. A simplified implementation of the pattern in java can be found below.

View1.java

import java.util.Observable;
import java.util.Observer;

public class View1 implements Observer
{
  public void update(Observable o, Object arg)
  {
    System.out.println("View 1: " + arg.toString());
  }
}

View2.java

import java.util.Observable;
import java.util.Observer;

public class View2 implements Observer
{
  public void update(Observable o, Object arg)
  {
    System.out.println("View 2: " + arg.toString());
  }
}

UserData.java

import java.util.Observable;

public class UserData extends MyObservable{
  private String name;
  private Long id;

  public UserData(){
    this.name = "";
    this.id = (long)0;
  }

  public String getName()
  {
    return name;
  }

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

  public Long getId()
  {
    return id;
  }

  public void setId(int id)
  {
    this.id = (long)id;
    setChanged();
    notifyObservers(id);
  }
}

TestMain.java

public class TestMain
{
  public static void main(String[] args)
  {
    UserData data = new UserData();
    View1 view1 = new View1();
    View2 view2 = new View2();
    data.addObserver(view1);
    data.addObserver(view2);

    data.setName("Lenard");
  }
}