Design Pattern: Prototype Pattern in Java

Prototype pattern is used to create a new object by cloning an existing one, to reduce the resource usage of object creation.

This article demonstrates Prototype pattern implementations in Java. Check the following examples.

Implementation

We can approach Prototype pattern implementation in multiple ways. Here are different ways for the implementation.

Method #1: Using Copy Constructor

Simple cloning of an object can be implemented in Java without using any Java cloning help using copy constructor. But that will have issues when the object becomes complex.

Here is the process of implementing Prototype pattern using copy constructor:

  • Create an interface for Prototype and declare “clone()” function, which returns the same type of object.
  • Implement the prototype of the subject/item class. 
  • In the item class, create a constructor that accepts the same type of object. Take all values from the param object and assign them to the variables of the class.
  • Implement the “clone()” method in the class. And return a new object of the same type.
  • While generating the clone, call the clone() method of an existing object and then cast it as the original item class.

Method #2: Using Cloneable Interface

For implementing cloning in Java properly, we need to implement the Cloneable (java.lang.Cloneable) interface.

Here is the process of Cloneable interface implementation.

  • Implement the “Cloneable” interface.
  • Create a method named “clone()”. This method does not take any param and the return type is “Object”.
  • Use try/catch to handle any exception in the cloning process. The cloning may through “CloneNotSupportedException” exception.
  • Use “super.clone()” to clone the object (inside try/catch).
  • Return the object that was obtained from “super.clone().

Here is a simple implementation of the clone function.

public Object clone() {
    Object requestClone = null;

    try {
        requestClone = super.clone();
    } catch (CloneNotSupportedException exception) {
        exception.printStackTrace();
    }

    return requestClone;
}

If we implement java.lang.Cloneable in parent class and define clone() method in a child, then the clone() also need to be defined in the parent, else the super.clone() will not work.

The clone() in Java performs a shallow copy. So any reference object inside the existing object, will not be cloned.

Let’s take a look at the following examples of Prototype pattern implementations in Java using the Cloneable interface.

Examples

Here are a few examples of Prototype pattern implementation and usage.

Example #1: Transport [Using Copy Constructor]

Let’s take an example of vehicles like cars, Planes, etc. In this example, we are implementing the cloning process using a copy constructor.

Prototype Interface

// Prototype.java

package com.bigboxcode.designpattern.prototype.transport;

public interface Prototype {

    Prototype clone();

}

Car Class

// Car.java

package com.bigboxcode.designpattern.prototype.transport;

public class Car implements Prototype {
    public int make;
    public String model;
    public String color;

    public Car() {

    }

    // This constructor is important for cloning implementation
    public Car(Car car) {
        this.make = car.make;
        this.model = car.model;
        this.color = car.color;
    }

    @Override
    public Prototype clone() {
        return new Car(this);
    }

    public String toString() {
        return "Make: " + make + " | Model: " + model + " | Color: " + color;
    }

}

Plane Class

// Plane.java

package com.bigboxcode.designpattern.prototype.transport;

public class Plane implements Prototype {
    public String model;
    public String color;

    public Plane() {

    }

    public Plane(Plane plane) {
        this.model = plane.model;
        this.color = plane.color;
    }

    @Override
    public Prototype clone() {
        return new Plane(this);
    }

    public String toString() {
        return "Model: " + model + " | Color: " + color;
    }
}

Demo

// Demo.java

package com.bigboxcode.designpattern.prototype.transport;

public class Demo {
    public static void main(String[] args) {
        Car car1 = new Car();
        car1.make = 2014;
        car1.model = "ABCD";
        car1.color = "Red";

        System.out.println(car1);

        System.out.println("---------------------------------------");

        // Clone existing object
        // and cast to Car
        Car carClone = (Car) car1.clone();
        carClone.model = "Some Different Model";
        carClone.color = "White";

        System.out.println(carClone);
    }
}

Output

Make: 2014 | Model: ABCD | Color: Red
---------------------------------------
Make: 2014 | Model: Some Different Model | Color: White

Example #2: Request Sender [Using Clonable Interface]

Let’s consider implementing a request-sending system, so that we can clone any existing request object and use that for a new request.

Request Interface [Abstract Class]

// Request.java

package com.bigboxcode.designpattern.prototype.request;

public abstract class Request implements Cloneable {

    public Object clone() {
        Object requestClone = null;

        try {
            requestClone = super.clone();
        } catch (CloneNotSupportedException exception) {
            exception.printStackTrace();
        }

        return requestClone;
    }

    abstract void send();
}

HttpReqeust Class

// HttpRequest.java

package com.bigboxcode.designpattern.prototype.request;

import java.util.HashMap;

enum RequestType {
    GET,
    POST,
    PUT,
    PATCH,
    DELETE,
}

public class HttpRequest extends Request {

    private String url;

    private RequestType type;
    private HashMap<String, String> header = new HashMap<>();
    private HashMap<String, String> body =new HashMap<>();

    public void setUrl(String url) {
        this.url = url;
    }

    public void setType(RequestType type) {
        this.type = type;
    }

    public void addHeader(String key, String value) {
        this.header.put(key, value);
    }

    public void removeHeader(String key) {
        this.header.remove(key);
    }

    public void addBody(String key, String value) {
        this.body.put(key, value);
    }

    public void removeBody(String key) {
        this.body.remove(key);
    }

    public void send() {
        System.out.println("Sending Request...");
        System.out.println("URL: " + url);
        System.out.println("Type: " + type);
        System.out.println("Headers: " + header);
        System.out.println("Body: " + body);


        // Write functional code to send request
    }

}

Demo

// Demo.java

package com.bigboxcode.designpattern.prototype.request;

public class Demo {
    public static void main(String[] args) {
        HttpRequest httpRequest = new HttpRequest();
        httpRequest.setUrl("https://bigboxcode.com/create-data-test");
        httpRequest.setType(RequestType.POST);
        httpRequest.addHeader("X-AUTH-TOKEN", "someTokeHere");
        httpRequest.addBody("code", "88C3ABK");

        httpRequest.send();

        System.out.println("\n----------------------------------------------\n");

        // Clone existing request
        // Cast the request as HttpRequest as the clone method returns Object
        HttpRequest secondRequest = (HttpRequest) httpRequest.clone();
        secondRequest.setType(RequestType.GET);
        secondRequest.setUrl("https://bigboxcode.com/some-other-endpoint");
        secondRequest.removeBody("code");

        secondRequest.send();
    }
}

Output

Sending Request...
URL: https://bigboxcode.com/create-data-test
Type: POST
Headers: {X-AUTH-TOKEN=someTokeHere}
Body: {code=88C3ABK}

----------------------------------------------

Sending Request...
URL: https://bigboxcode.com/some-other-endpoint
Type: GET
Headers: {X-AUTH-TOKEN=someTokeHere}
Body: {}

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Prototype pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.