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

Return to top