The most successful people in any walks of lives may not be the most talented ones but are definately the most passionate & dedicated ones.

Tuesday, September 14, 2010

kiss - Prototype design pattern

Before I start let me make kiss very clear. Its an acronym for "keep it short & simple". I found this pattern fairly interesting and in fact got into the realm of "cloning" in java due to this, so thought to share my learning and experiences on this design pattern.

What is a prototype design pattern?
In this point we should be exploring the intent of the prototype design pattern, which is :-
  • It specifies the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
  • This pattern co-opt one instance of a class for use as a breeder of all future instances.
  • This pattern sees the java "new" operator as cumbersome.
Okayy, the jist is, we create an object of a class once & then clone the object another instance is required.


Why to use prototype design pattern?
We would use a pattern only if its benefits us/our solution in some way or the other. So benifits of prototype pattern are:-
  • Whenever object initialization is expensive [of-course to the compiler in terms of time 'n' resources] and you anticipate few variations on the initialization parameters, there this pattern could be used.
  • It allows a developer to add / remove attributes at runtime.
  • It allows a developer to specify new objects in terms of varying values.

Where to use a prototype pattern?
  1. When there are many subclasses that differ only in the kind of objects.
  2. A sample scenario:- "There are two class instance(say) that need to be populated with some values, retrieved from the database.The first instance contains values sorted on some key value,while the other is sorted base on some other key(but containing the same data). Now there can be two mechanism for fulfilling the above requirement:- a) Sort the values from the database and then populate in the class,hence the database retrieval is performed 2 times(or n times for n instances). Or b) get the values from the database(one time), populate a single instance, override the clone() method,and then perform cloning."

Sample implementation of prototype pattern [in java programming language] :-
  • Here I have used 8 [classes and interfaces] to provide a sample implementation.
  • The purpose of each class and interface is explained at the beginning of the source code along with other important points.
  • Here you can be starting at PrototypeDemo.java class which has the main() method as a starting point.

(1) ************ start of Constants.java ************
/**
* Purpose:- To place constants used through-ouot the example for Prototype pattern at one place.
*/

package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/
public class Constants {

public static final String SQUARE = "Square";
public static final String TRIANGLE = "Triangle";
public static final String RECTANGLE = "Rectangle";

public static final int numOfMasterObjects = 10;

}
************ end of Constants.java ************


(2) ************ start of Prototype.java ************
/**
* Purpose:- The purpose of this class is to provide an agreement (thereby abstraction also) so that the class which implement this
* interface have to override the declared methods.
*
* Notes:- (1) By default (implictly) interface members are public, static and final i.e. they are constants and coan't be modified.
* (2) They support the concept of multiple inheritence.
*/

package prototypePattern;

/**
* @author Vinay K Mudgil
*/

public interface Prototype {

//The purpose is to get the name which is to be cloned.
public String getName();

//The purpose is that class implementing this interface should override the clone method.
public Object clone() throws CloneNotSupportedException;
}

************ end of Prototype.java ************


(3) ************ start of PrototypeDemo.java ************
/**
* Purpose:- Class which is used to show the "prototype" pattern in java works :)
* i.e. its a client application which uses a prototype design pattern
*/

package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/
public class PrototypeDemo {

//used to load the
public static void loadMasterObjectsAtBegining() {
ProtoTypeMaster.addPrototype(new Triangle());
ProtoTypeMaster.addPrototype(new Square());
ProtoTypeMaster.addPrototype(new Rectangle());
}

public static void main(String[] args) throws CloneNotSupportedException {
System.out.println("starting execution now.....");
Object [] clonedObjectArray = new Object[args.length];
int count=0;

//intialize
PrototypeDemo.loadMasterObjectsAtBegining();

//For each command-line argument, lets see if we can create a clone.
for(int i=0;i if( (ProtoTypeMaster.findAndClone(args[i]) ) != null) {
clonedObjectArray[count] = ProtoTypeMaster.findAndClone(args[i]);
count++;
}

}

//now, just for sample, lets execute draw method to show that we created cloned objects.
for(int i=0; i if (clonedObjectArray[i] != null)
((UtilityFunctions) clonedObjectArray[i] ).draw();
}

} //end of main method

}//end of class
************ end of ************


(4) ************ start of ProtoTypeMaster.java************
/**
* Purpose:- To hold objects of class which are to be cloned.
*/

package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/

public class ProtoTypeMaster extends Constants{

private static Prototype [] masterObjectHolder = new Prototype [Constants.numOfMasterObjects];

//variable which holds the current count of
private static int currentCount = 0;

/*
* Purpose:- Add relevant object to the masterObjectHolder
*/
public static void addPrototype(Prototype pObj) {

if(currentCount < Constants.numOfMasterObjects)
masterObjectHolder[currentCount++] = pObj;
else
System.out.println("This Addition would exceedes max. number of allowed objects which can be Prototyped and hence rejecting this addition");
} //end of addPrototype() method


/*
* Purpose:- To search for the relevant class to be cloned and then clone that class and return the cloned instance.
*/
public static Object findAndClone (String classNameToBeCloned) throws CloneNotSupportedException {

//first search in the masterObjectHolder that which relevant class is to be cloned
for(int i=0; i < currentCount; i++) {

if ( masterObjectHolder[i].getName().equals(classNameToBeCloned) ) {
//now that our search is successful, lets clone the object and return it.
return masterObjectHolder[i].clone();
}
}

System.out.println("class name which you supplied at \"runtime\" couldn't be found in the masterObjectHolder and hence can't be cloned");
return null;
}


} //end of class
************ end of ProtoTypeMaster.java ************


(5) ************ start of Rectangle.java ************
/**
* Purpose:- To provide a class (for testing) which can be cloned.
*/
package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/
public class Rectangle extends Constants implements Prototype, UtilityFunctions, Cloneable {

public String getName() {
return Constants.RECTANGLE;
}

public void draw() {
System.out.println("Drawing a Rectangle");
}

public Object clone() throws CloneNotSupportedException {
return (Rectangle) super.clone();
}

}//end-of-class
************ end of Rectangle.java ************


(6) ************ start of Square.java ************
/**
* Purpose:- To provide a class (for testing) which can be cloned.
*/
package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/
public class Square extends Constants implements Prototype, UtilityFunctions, Cloneable {
public String getName() {
return Constants.SQUARE;
}

public void draw() {
System.out.println("Drawing a Square");
}

public Object clone() throws CloneNotSupportedException {
return (Square) super.clone();
}

}//end-of-class
************ end of Square.java ************


(7) ************ start of Triangle.java************
/**
* Purpose:- To provide a class (for testing) which can be cloned.
*/

package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/

public class Triangle extends Constants implements Prototype, UtilityFunctions, Cloneable {
public String getName() {
return Constants.TRIANGLE;
}

public void draw() {
System.out.println("Drawing a Triangle");
}

public Object clone() throws CloneNotSupportedException {
return (Triangle) super.clone();
}

}//end-of-class
************ end of Triangle.java ************


(8) ************ start of UtilityFunctions.java ************
/**
* Purpose:- This interface is created to give you an idea that in real world scenerio's this interface is overridden by class
* to provide their own implementation of a methods
*/

package prototypePattern;

/**
* @author Vinay K Mudgil
*
*/

public interface UtilityFunctions {

//sample method which every first concrete sub-class would provide an implementation for.
public void draw();
}
************ end of UtilityFunctions.java ************


Please feel free to comment on concepts &
sample code snippet provided above. Happy to learn from you.

Thanks !!!

2 comments:

  1. Indentation is badly required when you have so many classes. . Rest everything else is good.

    ReplyDelete
  2. Agreed Jatin. Point well taken & appreciated.

    ReplyDelete