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.
Table of Contents
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.
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.