Prototype Patterns

Creational Patterns - Prototype Pattern

The prototype means making a clone. This implies cloning of an object to avoid creation. If the cost of creating a new object is large and creation is resource intensive, we clone the object. We use the interface Cloneable and call its method clone() to clone the object.

Again let’s try and understand this with the help of a non-software example. I am stressing on general examples throughout this write-up because I find them easy to understand and easy to accept as we all read and see them in day-to-day activity. The example here we will take will be of a plant cell. This example is a bit different from the actual cloning in a way that cloning involves making a copy of the original one. Here, we break the cell in two and make two copies and the original one does not exist. But, this example will serve the purpose. Let’s say the Mitotic Cell Division in plant cells.
Let’s take a class PlantCell having a method split(). The plant cell will implement the interface Cloneable.

Following is the sample code for class PlantCell.

PlantCell.java

package creational.builder;

/**
* Shows the Mitotic cell division in the plant cell.
*/
public class PlantCell implements Cloneable {

  public Object split() {
    try {
      return super.clone();
}catch(Exception e) {
System.out.println("Exception occured: "+e.getMessage());
return null;
}
    }
}// End of class

Now let’s see, how this split method works for PlantCell class. We will make another class CellDivision and access this method.

CellDivision.java

package creational.prototype;
/**
* Shows how to use the clone.
*/
public class CellDivision {
  public static void main(String[] args) {
PlantCell cell = new PlantCell();

// create a clone
PlantCell newPlantCell = (PlantCell)cell.split();
}

}// End of class

One thing is you cannot use the clone as it is. You need to instantiate the clone before using it. This can be a performance drawback. This also gives sufficient access to the data and methods of the class. This means the data access methods have to be added to the prototype once it has been cloned.

Prototype patterns

posted Feb 17, 2011, 10:00 PM by Ky Vo   [ updated Feb 17, 2011, 10:00 PM ]

Prototype


Definition

Cloning an object by reducing the cost of creation.

Where to use & benefits

Example

Dynamic loading is a typical object-oriented feature and prototype example. For example, overriding method is a kind of prototype pattern.

interface Shape {
public void draw();
}
class Line implements Shape {
public void draw() {
System.out.println("line");
}
}
class Square implements Shape {
public void draw() {
System.out.println("square");
}
}
class Circle implements Shape {
public void draw() {
System.out.println("circle");
}
}
class Painting {
public static void main(String[] args) {
Shape s1 = new Line();
Shape s2 = new Square();
Shape s3 = new Circle();
paint(s1);
paint(s2);
paint(s3);
}
static void paint(Shape s) {
s.draw();
}
}
----------------------------
If we want to make code more readable or do more stuff, we can code the paint method in the following way:

static void paint(Shape s){
if ( s instanceof Line)
s.draw();
//more job here
if (s instanceof Square)
s.draw();
//more job here
if (s instanceof Circle)
s.draw();
//more job here
}

 C:\ Command Prompt

 
C:\> java Painting
line
square
circle

The paint method takes a variable of Shape type at runtime. The draw method is called based on the runtime type.

Overloading method is a kind of prototype too.

class Painting {
public void draw(Point p, Point p2) {
//draw a line
}
public void draw(Point p, int x, int y) {
//draw a square
}
public void draw(Point p, int x) {
//draw a circle
}
}

The draw method is called to draw the related shape based on the parameters it takes.

The prototype is typically used to clone an object, i.e. to make a copy of an object. When an object is complicated or time consuming to be created , you may take prototype pattern to make such object cloneable. Assume the Complex class is a complicated, you need to implement Cloneable interface and override the clone method(protected Object clone()).

class Complex implements Cloneable {
int[] nums = {1,2,3,4,5};
public Object clone() {
try {
return super.clone();
}catch(CloneNotSupportedException cnse) {
System.out.println(cnse.getMessage());
return null;
}
}
int[] getNums() {
return nums;
}
}
class Test {
static Complex c1 = new Complex();
static Complex makeCopy() {
return (Complex)c1.clone();
}
public static void main(String[] args) {
Complex c1 = makeCopy();
int[] mycopy = c1.getNums();
for(int i = 0; i < mycopy.length; i++)
System.out.print(mycopy[i]);
}
}

 C:\ Command Prompt

 
C:\> java Test
12345

Cloning is a shallow copy of the original object. If the cloned object is changed, the original object will be changed accordingly. See the following alteration.

class Complex implements Cloneable {
int[] nums = {1,2,3,4,5};
public Object clone() {
try {
return super.clone();
}catch(CloneNotSupportedException cnse) {
System.out.println(cnse.getMessage());
return null;
}
}
int[] getNums() {
return nums;
}
}
class Test {
Complex c1 = new Complex();
Complex makeCopy() {
return (Complex)c1.clone();
}
public static void main(String[] args) {
Test tp = new Test();
Complex c2 = tp.makeCopy();
int[] mycopy = c2.getNums();
mycopy[0] = 5;


System.out.println();
System.out.print("local array: ");
for(int i = 0; i < mycopy.length; i++)
System.out.print(mycopy[i]);
System.out.println();

System.out.print("cloned object: ");
for(int ii = 0; ii < c2.nums.length; ii++)
System.out.print(c2.nums[ii]);
System.out.println();

System.out.print("original object: ");
for(int iii = 0; iii < tp.c1.nums.length; iii++)
System.out.print(tp.c1.nums[iii]);
}

 C:\ Command Prompt

 
C:\> java Test

local array: 52345
cloned object: 52345
original object: 52345

To avoid such side effect, you may use a deep copy instead of a shallow copy. The following shows the alteration to the above example, note that the Complex class doesn't implement Cloneable interface.

class Complex {
int[] nums = {1,2,3,4,5};
public Complex clone() {
return new Complex();
}

int[] getNums() {
return nums;
}
}
class Test2 {
Complex c1 = new Complex();
Complex makeCopy() {
return (Complex)c1.clone();
}
public static void main(String[] args) {
Test2 tp = new Test2();
Complex c2 = tp.makeCopy();
int[] mycopy = c2.getNums();
mycopy[0] = 5;

System.out.println();
System.out.print("local array: ");
for(int i = 0; i < mycopy.length; i++)
System.out.print(mycopy[i]);
System.out.println();

System.out.print("cloned object: ");
for(int ii = 0; ii < c2.nums.length; ii++)
System.out.print(c2.nums[ii]);
System.out.println();

System.out.print("original object: ");
for(int iii = 0; iii < tp.c1.nums.length; iii++)
System.out.print(tp.c1.nums[iii]);
}
}
 C:\ Command Prompt
 
C:\> java Test2

local array: 52345
cloned object: 52345
original object: 12345

1-1 of 1