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
Comments