Prototype Design Pattern

Prototype Design Pattern

The Prototype Design Pattern is a creational design pattern that allows cloning objects, thus avoiding the cost of creating objects from scratch. It involves creating new objects by copying an existing object, known as the prototype. This pattern is useful when the cost of creating an object is expensive or complex.

Prototype Design Pattern

Advantages of Prototype Design Pattern

Performance Improvement

   Cloning an object is often more efficient than creating a new object from scratch, especially if the object creation process is resource-intensive.

Simplifies Object Creation:

   It simplifies the creation of objects that have many configuration options by copying an existing prototype instead of configuring a new instance.

Reduces Subclassing

   Reduces the need for creating a hierarchy of subclasses to instantiate different objects, as different clones can be customized after cloning.

Runtime Object Creation:

    Allows dynamic and flexible object creation at runtime, which can be modified without altering the code structure.

Disadvantages of Prototype Design Pattern

Complex Cloning Process:

   Implementing the cloning process can be complex, especially for objects with complex inner structures or objects that contain circular references.

Deep vs. Shallow Copy

   Deciding between shallow and deep copying can be tricky, and deep copying can be expensive if the object graph is large.

Potential for Unintended Changes

   There is a risk of unintended changes to cloned objects if not handled properly, as clones share the same state if a shallow copy is used.

Example - Prototype Design Pattern:
java
import java.util.HashMap;
import java.util.Map;

// Step 1: Create an abstract class implementing Cloneable interface
abstract class Shape implements Cloneable {
    private String id;
    protected String type;

    abstract void draw();

    public String getType() {
        return type;
    }

    public String getId() {
        return id;
    }

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

    @Override
    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

// Step 2: Create concrete classes extending the above class
class Rectangle extends Shape {
    public Rectangle() {
        type = "Rectangle";
    }

    @Override
    void draw() {
        System.out.println("Inside Rectangle::draw() method.");
    }
}

class Circle extends Shape {
    public Circle() {
        type = "Circle";
    }

    @Override
    void draw() {
        System.out.println("Inside Circle::draw() method.");
    }
}

class Square extends Shape {
    public Square() {
        type = "Square";
    }

    @Override
    void draw() {
        System.out.println("Inside Square::draw() method.");
    }
}

// Step 3: Create a class to get concrete classes from the database and store them in a Hashtable
class ShapeCache {
    private static Map<String, Shape> shapeMap = new HashMap<>();

    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }

    // For each shape run database query and create shape
    // shapeMap.put(shapeKey, shape);
    // For example, we are adding three shapes
    public static void loadCache() {
        Circle circle = new Circle();
        circle.setId("1");
        shapeMap.put(circle.getId(), circle);

        Square square = new Square();
        square.setId("2");
        shapeMap.put(square.getId(), square);

        Rectangle rectangle = new Rectangle();
        rectangle.setId("3");
        shapeMap.put(rectangle.getId(), rectangle);
    }
}

// Step 4: Use the ShapeCache to get clones of shapes
public class PrototypePatternDemo {
    public static void main(String[] args) {
        ShapeCache.loadCache();

        Shape clonedShape1 = ShapeCache.getShape("1");
        System.out.println("Shape : " + clonedShape1.getType());
        clonedShape1.draw();

        Shape clonedShape2 = ShapeCache.getShape("2");
        System.out.println("Shape : " + clonedShape2.getType());
        clonedShape2.draw();

        Shape clonedShape3 = ShapeCache.getShape("3");
        System.out.println("Shape : " + clonedShape3.getType());
        clonedShape3.draw();
    }
}

Explanation

  • Step 1: Create an abstract Shape class that implements Cloneable interface and provides a method for cloning objects.
  • Step 2: Create concrete classes (Rectangle, Circle, Square) that extend the Shape class and implement the draw method.
  • Step 3: Create a ShapeCache class that stores shape objects in a Hashtable and allows retrieving clones of these shapes.
  • Step 4: In the PrototypePatternDemo class, load the cache with shape objects and retrieve clones using the ShapeCache.

Summary

The Prototype Design Pattern is useful for creating new objects by cloning existing ones, improving performance and simplifying object creation. It offers advantages like performance improvement, simplified object creation, reduced subclassing, and flexible runtime object creation. However, it also comes with complexities in the cloning process, challenges with deep vs. shallow copying, and potential for unintended changes in cloned objects. By following this pattern, you can create flexible and efficient object creation mechanisms in your applications.

Homepage

Readmore