Prototype Design Pattern

The Prototype pattern is a Creational Design Pattern that avoids costly creation of objects. The concept of this is to copy an existing object versus creating a new object all together. This is typically done using the clone() method from the Clonable interface. This design pattern is useful when creating objects becomes too costly or they take too much time.

Although you will be creating copies of an object, each instance will be unique. This is what’s called a Deep Copy. A deep copy will return a brand new object to a new instance, rather than a reference to the original object (Shallow Copy).  Shallow Copies are dangerous because you could change the parameters in one object and it would reflect in both the copied and original object. The construction of the objects will be handle by a Registry class.

We will implement a Device example of the Prototype pattern in Java. We will create an abstract class called Device that implements Clonable from the Java API. The DeviceRegistry  class will contain a static method that returns a cloned instance of Device.



1. Create an abstract class called Device. This will contain getters and setters for id and name. This will contain abstract methods powerOn() and addDevice() that will be overridden by sub-classes.

public abstract class Device implements Cloneable {
    private int id;
    private String deviceName;

    abstract void powerOn();
    abstract void addDevice();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

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

}


2. Add sub-classes Iphone and Pixel.

public abstract class Device implements Cloneable {
    private int id;
    private String deviceName;

    abstract void powerOn();
    abstract void addDevice();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

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

}
public class Pixel extends Device {
    @Override
    void powerOn() {
        System.out.println("Powered On Pixel");
    }

    @Override
    void addDevice() {
        System.out.println("Added Pixel Device");
    }
}


3. Create the Registry class that will contain a getDevice() method that will clone the Device object into a new instance.

package Prototype;

import java.util.HashMap;
import java.util.Map;

public class DeviceRegistry {

    private static Map<Integer, Device> devices = new HashMap();

    /**
     * Clones a Device object into a new instance by deviceId.
     *
     * @param deviceId - Id of device we want to clone.
     * @return
     */
    public static Device getDevice(Integer deviceId) {
        Device device = null;
        try {
            device = (Device) (devices.get(deviceId)).clone();
        } catch (CloneNotSupportedException ex) {

        }
        return device;
    }

    /**
     * Loads devices into objects. In a real application we would pull data from a database.
     */
    public static void loadDevices() {
        Iphone iphone = new Iphone();
        iphone.setId(1);
        iphone.setDeviceName("Iphone 8 Plus");
        devices.put(iphone.getId(), iphone);

        Pixel pixel = new Pixel();
        pixel.setId(2);
        pixel.setDeviceName("Google Pixel 4");
        devices.put(pixel.getId(), pixel);
    }
}

4. Create the client class. This will clone a Device instance into Iphone and Pixel.

public class ProtoypeClient {
    public static void main(String[] args) {
        DeviceRegistry.loadDevices();

        Device iphone = DeviceRegistry.getDevice(1);
        System.out.println(iphone);
        System.out.println(iphone.getDeviceName());
        iphone.addDevice();
        iphone.powerOn();
        System.out.println();

        Device pixel = DeviceRegistry.getDevice(2);
        System.out.println(pixel);
        System.out.println(pixel.getDeviceName());
        pixel.addDevice();
        pixel.powerOn();

    }
}
Prototype.Iphone@1b6d3586
Iphone 8 Plus
Added Iphone
Powered On Iphone

Prototype.Pixel@4554617c
Google Pixel 4
Added Pixel Device
Powered On Pixel

Process finished with exit code 0