Learnitweb

Prototype design pattern in Java

1. Introduction

It specifies the kinds of objects to create using a prototypical instance and creates new objects by copying this prototype.

This pattern offers an alternative approach to creating new objects by duplicating or cloning an existing instance, rather than building a new one from scratch. This allows you to bypass the overhead associated with constructing a brand-new object. Why is this approach valuable? There are several reasons:

  • Some resources required for creating an object may be scarce or difficult to obtain.
  • Constructing a new instance can be a time-intensive process.

The key idea behind this pattern, as highlighted in the GoF definition, is to create a new object by using an existing object as a template.

In practice, this pattern typically involves an abstract class or interface, known as the prototype, which defines a cloning method. Concrete implementations of the prototype provide the actual cloning behavior. Clients can then create new objects by requesting a prototype instance to clone itself.

2. Key Concepts

  • Prototype:
    • An interface or abstract class that declares the cloning method.
    • Used as a template for creating new objects.
  • Concrete Prototype:
    • Implements the Prototype interface and provides the actual implementation of the cloning method.
  • Client:
    • Uses the prototype to create new objects by invoking the cloning method.

3. Steps to Implement the Prototype Pattern

Step 1: Define the Prototype Interface

The prototype interface declares the method for cloning objects. In Java, this can be done using the Cloneable interface.

public interface Prototype extends Cloneable {
    Prototype clone();
}

Step 2: Create Concrete Prototypes

Concrete prototypes implement the cloning logic and define the actual objects that can be cloned.

public class Circle implements Prototype {
    private int radius;

    public Circle(int radius) {
        this.radius = radius;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    @Override
    public Circle clone() {
        return new Circle(this.radius);
    }

    @Override
    public String toString() {
        return "Circle with radius: " + radius;
    }
}

public class Rectangle implements Prototype {
    private int length;
    private int width;

    public Rectangle(int length, int width) {
        this.length = length;
        this.width = width;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    @Override
    public Rectangle clone() {
        return new Rectangle(this.length, this.width);
    }

    @Override
    public String toString() {
        return "Rectangle with length: " + length + ", width: " + width;
    }
}

Step 3: Create the Client

The client interacts with prototypes to create new objects by cloning.

public class PrototypePatternDemo {
    public static void main(String[] args) {
        // Create initial objects
        Circle originalCircle = new Circle(10);
        Rectangle originalRectangle = new Rectangle(20, 30);

        // Clone the objects
        Circle clonedCircle = originalCircle.clone();
        Rectangle clonedRectangle = originalRectangle.clone();

        // Modify the cloned objects
        clonedCircle.setRadius(15);
        clonedRectangle.setLength(25);

        // Display the objects
        System.out.println("Original Circle: " + originalCircle);
        System.out.println("Cloned Circle: " + clonedCircle);

        System.out.println("Original Rectangle: " + originalRectangle);
        System.out.println("Cloned Rectangle: " + clonedRectangle);
    }
}

Output

Original Circle: Circle with radius: 10
Cloned Circle: Circle with radius: 15
Original Rectangle: Rectangle with length: 20, width: 30
Cloned Rectangle: Rectangle with length: 25, width: 30

4. Key Benefits

  • Reduced Object Creation Cost: Avoids the overhead of creating new objects from scratch, especially if initialization is resource-intensive.
  • Simplified Object Creation: Instead of writing complex object creation logic repeatedly, cloning provides a straightforward way to duplicate objects.
  • Supports Runtime Configuration: Allows dynamic creation of objects at runtime, which is helpful in scenarios where object configurations are not predefined.
  • Encapsulation of Object State: By cloning, the client doesn’t need to know the details of how an object is constructed.

5. Use Cases

  • Game Development: Creating multiple enemy or character objects with slight variations.
  • Prototyping in GUI Applications: Duplicating user interface elements (e.g., buttons, windows) with minor modifications.
  • Database Connections: Cloning connection objects for reuse, avoiding the overhead of establishing new connections.
  • Document Editors: Copying existing documents, shapes, or text with minor tweaks.

6. Comparison with Other Patterns

AspectPrototype PatternFactory Method Pattern
Object CreationClones an existing object.Creates new objects through factory methods.
Use CaseWhen creating an object is costly or complex.When object creation depends on subclasses.
ComplexitySimpler for cloning; avoids repetitive initialization.More complex due to the need for subclassing.