Prototype Design Pattern

The Prototype Design Pattern is used for cloning an existing object, if the cost of creating a new object of a class is complicated and resource expensive.

Here, we do not have to repeat the complex object building process to get new object of a class. This design pattern comes under creational design pattern as it provides one of the best ways to create clone of complex objects.

Advantages of Prototype Pattern

  • It hides the complexities of making new instance of a class from client.
  • Client specifies the kind of object it requires using a prototypical instance. Client is unaware of the type of object it will get.
  • It improves the performance of the system. If the cost of creating a new instance is more because of resource intensive operations(like running a database query), it is better to clone an existing prototype object.
  • One instance of a class is used to produce all future instances.

When we should use Prototype pattern

  • When the logic of creating a new object is complex and it requires resource extensive operations to be performed.
  • When we want to hide the logic of object creation and its representation from client.
  • When the classes to instantiate are specified at run-time.
  • When objects of a class can have only few different state(lets say N). It is more convenient to first create N prototype object of different states and clone them later when we need objects of different states.

Implementation of Prototype Design Pattern

We will create an abstract class Bird and it’s concrete implementation Parrot.java, Sparrow.java and Eagle.java. Each concrete implementation of Bird class will override cloneObject method.

Prototype_Pattern

Prototype Design Pattern

Bird.java
public abstract class Bird implements Cloneable  {
    protected String name;
  
    public String getName() {
        return name;
    }
     
    public void setName(String name) {
        this.name = name;
    }
  
    public abstract Bird cloneObject() throws CloneNotSupportedException;
}

Prototype Design Pattern 1

Parrot.java
public class Parrot extends Bird {
  
    public Parrot() {
        name = PrototypeFactory.PARROT;
    }
  
    @Override
    public Bird cloneObject() throws CloneNotSupportedException {
        System.out.println("Cloning a Parrot object");
        return (Bird) super.clone();
    }
}
Eagle.java
public class Eagle extends Bird {
  
    public Eagle() {
        name = PrototypeFactory.EAGLE;
    }
  
    @Override
    public Bird cloneObject() throws CloneNotSupportedException {
        System.out.println("Cloning an Eagle object");
        return (Bird) super.clone();
    }
}
Sparrow.java
public class Sparrow extends Bird {
  
    public Sparrow() {
        name = PrototypeFactory.SPARROW;
    }
  
    @Override
    public Bird cloneObject() throws CloneNotSupportedException {
        System.out.println("Cloning a Sparrow object");
        return (Bird) super.clone();
    }
}

PrototypeFactory class will create prototype instances of Parrot, Sparrow and Eagle stores then in a HashMap. The getBirdInstance method first get the prototype instance of requested bird object from HashMap and the returns a copy of it.

Prototype Design Pattern 2

import java.util.Map;
import java.util.HashMap;
 
public class PrototypeFactory {
    public static final String PARROT = "Parrot";
    public static final String SPARROW = "Sparrow";
    public static final String EAGLE = "Eagle";
 
    private Map<String, Bird> prototypeList = new HashMap<String, Bird>();
     
    public void initialize() {   
     prototypeList.put(PrototypeFactory.PARROT, new Parrot());
     prototypeList.put(PrototypeFactory.SPARROW, new Sparrow());
     prototypeList.put(PrototypeFactory.EAGLE, new Eagle());
    }
  
    public Bird getBirdInstance(String name) throws CloneNotSupportedException {
        return (Bird)prototypeList.get(name).cloneObject();
    }
}

PrototypePatternExample class uses PrototypeFactory object to create object of Parrot, Sparrow and Eagle classes.

public class PrototypePatternExample {
    public static void main(String[] args) {
        PrototypeFactory factory = new PrototypeFactory();
        factory.initialize();
        try {
            factory.getBirdInstance(PrototypeFactory.PARROT);
            factory.getBirdInstance(PrototypeFactory.SPARROW);
            factory.getBirdInstance(PrototypeFactory.EAGLE);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

Output

Cloning a Parrot object
Cloning a Sparrow object
Cloning an Eagle object