blogger templates blogger widgets
This is part of a list of blog posts.
To browse the contents go to

Creational Design Patterns


Singleton pattern

Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine.

So instead of doing
Worker worker = new Worker(); 
in your client. You should be doing this.

Worker worker = Worker.getInstance();
worker.doWork();
worker = Worker.getInstance();
worker.doWork();

Eager Initialization - the instance of Singleton Class is created at the time of class loading


class Worker {

	private static final Worker instance = new Worker();

	private int counter = 0;

	private Worker() {
		println("worker initialized");
	}

	public static Worker getInstance() {
		return instance;
	}

	public void doWork() {
		println("counter: "+counter++);
	}
}


Static block Initialization - another way of eager initialization, the instance of Singleton Class is created at the time of class loading


class Worker {

    private static final Worker instance;

	private int counter = 0;

    static {
        try {
            instance = new Worker();
        } catch (Exception e) {
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
    }

    private Worker() {
        println("worker initialized");
    }

    public static Worker getInstance() {
        return instance;
    }

    public void doWork() {
        println("counter: "+counter++);
    }
}


Lazy Initialization


class Worker {

	private static Worker instance;

	private int counter = 0;

	private Worker() {
		println("worker initialized");
	}

	public static Worker getInstance() {
		if(instance == null) {
			instance = new Worker();
		}
		return instance;
	}

	public void doWork() {
		println("counter: "+counter++);
	}
}


Thread safe singleton


class Worker {

	private static Worker instance;

	private int counter = 0;

	private Worker() {
		println("worker initialized");
	}

	public static synchronized Worker getInstance() {
		if(instance == null) {
			instance = new Worker();
		}
		return instance;
	}

	public void doWork() {
		println("counter: "+counter++);
	}
}


Thread safe - double checked locking - it avoid unnecessary wait on the lock on the method


class Worker {

	private static Worker instance;

	private int counter = 0;

	private Worker() {
		println("worker initialized");
	}

	public static Worker getInstance() {
		if(instance == null) {
			synchronized (Worker.class) {
				if(instance == null) {
					instance = new Worker();
				}
			}
		}
		return instance;
	}

	public void doWork() {
		println("counter: "+counter++);
	}
}


Initialization-On-Demand Holder (Bill Pugh)

Prior to Java 5, java memory model had a lot of issues and above approaches used to fail in certain scenarios where too many threads try to get the instance of the Singleton class simultaneously.
This is lazy at the sametime thread safe.

As the class initialization phase is guaranteed by the JLS to be serial,
i.e., non-concurrent, so no further synchronization is required in the static getInstance() method during loading and initialization.


class WorkerHelper {

	public static Worker getInstance() {
		return Worker.instance;
	}

	private static class Worker {

		private int counter = 0;

		private static final Worker instance = new Worker();

		private Worker() {
			println("worker initialized");
		}

		public void doWork() {
			println("counter: "+counter++);
		}
	}

}

Reflection can be used to destroy all the above singleton implementation approaches but enums overcome this situation


Enums - Singletons on steroids


enum Worker {

	instance;

	private int counter=0;

	public void doWork() {
		println("counter: "+counter++);
	}
}


Factory pattern

Client:

Animal dog = AnimalFactory.createAnimal("Dog");
println(dog.toString());

Factory and implementation:

class AnimalFactory {

	public static Animal createAnimal(String type) {
		Animal animal = null;
		if("Dog".equals(type)){
			animal = new Dog("Boxi");
			return animal;
		}
		return animal;
	}
}

abstract class Animal {

	private String name;

	public abstract String getType();

	public String toString(){
		return "Type: "+getType()+", Name: "+getName();
	}

	public String getName() {
		return name;
	}

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


class Dog extends Animal {

	Dog(String name){
		setName(name);
	}

	@Override
	public String getType() {
		return "Dog";
	}
}
Output:
[main] Type: Dog, Name: Boxi
Examples within JDK: Calender ResourceBundle NumberFormat Abstract Factory pattern Client:

AnimalFactory factory = new DogFactory();
Animal dog = factory.createAnimal();
println(dog.toString());
Factory and impl:

interface AnimalFactory {
	Animal createAnimal();
}


class DogFactory implements AnimalFactory {
	public Animal createAnimal(){
		return new Dog("Boxi");
	}
}

abstract class Animal {

	private String name;

	public abstract String getType();

	public String toString(){
		return "Type: "+getType()+", Name: "+getName();
	}

	public String getName() {
		return name;
	}

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


class Dog extends Animal {

	Dog(String name){
		setName(name);
	}

	@Override
	public String getType() {
		return "Dog";
	}
}
Examples within JDK: javax.xml.parsers.DocumentBuilderFactory javax.xml.transform.TransformerFactory javax.xml.xpath.XPathFactory Builder pattern when the Object contains a lot of attributes. Using default values and lots of setters in factory pattern gets complex or sometimes inconsistent. Client:

Dog dog = new DogBuilder().setColor("black").setWeight("10kg").build();
println(dog.toString());

abstract class Animal {

	private String name;

	public abstract String getType();

	public String toString(){
		return "Type: "+getType()+", Name: "+getName();
	}

	public String getName() {
		return name;
	}

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


class Dog extends Animal {

	private String color;
	private String weight;

	//Dog class exposes only one public constructor and that takes in a DogBuilder
	//Any other constructor is usually made private

	Dog(DogBuilder builder) {
		this.color = builder.color;
		this.weight =  builder.weight;
	}

	@Override
	public String getType() {
		return "Dog";
	}

	public String getColor() {
		return color;
	}

	public String getWeight() {
		return weight;
	}

	public String toString(){
		return super.toString()+", Color: "+getColor()+", Weight: "+getWeight();
	}

	//We don't provide the setters on the Dog class
	//As that is taken care by the DogBuilder
	//any other business logic related to building a Dog class goes into it's builder

	static class DogBuilder {

		String color;
		String weight;

		public DogBuilder setColor(String color) {
			this.color = color;
			return this;
		}

		public DogBuilder setWeight(String weight) {
			this.weight = weight;
			return this;
		}

		public Dog build() {
			return new Dog(this);
		}
	}
}
JDK: java.lang.StringBuilder#append() java.lang.StringBuffer#append() Prototype pattern when the Object creation is a costly affair and requires a lot of time and resources and you have a similar object already existing. So this pattern provides a mechanism to copy the original object to a new object and then modify it according to our needs. Client:

Animals animals = new Animals();
animals.loadNames();
println(animals.getNames());
Animals new_animals = (Animals)animals.clone();
//you don't have to call loadNames again because that data
//too is cloned into the object
println(new_animals.getNames());

class Animals implements Cloneable {

	private List names;

	Animals() {
		names = new ArrayList();
	}

	public String toString(){
		return "Name: "+getNames();
	}

	public List getNames() {
		return names;
	}

	public void setNames(List names) {
		this.names = names;
	}

	public void loadNames() {
		//reads data from some data source like DB into list
		names.add("boxi");
		names.add("peggy");
		names.add("blacky");
	}

	@Override
	public Object clone() throws CloneNotSupportedException {

		Animals animals = new Animals();

		//this stores the same reference to list - don't do this - this is not deep copy
		//animals.setNames(names);

		//this is deep copy
		List temp = new ArrayList();
		for(String name: getNames()){
			temp.add(name);
		}
		animals.setNames(temp);

		return animals;
	}
}

No comments:

Post a Comment