- What is It?
- Where and Why do We Use It?
- Big Problem Solved by It
- Working Flow and Shallow Vs Deep Copy
- Key Components
- Principle Method
- Implement It in Java
- Examples of Real-World Scenario
- Use cases of
- Advantages & Disadvantages
The Prototype Design Pattern is a creational design pattern. It allows you to create new objects by copying existing ones (prototypes), instead of creating them from scratch. This pattern is useful when the cost of creating a new object is high, and you can reuse existing objects as templates.
- Why Use It?
- Expensive Object Creation: When creating an object involves significant resource consumption (e.g., database calls, network operations, or large file processing).
- Frequent Object Cloning: When objects with similar configurations are frequently needed.
- Avoid Constructor Complexity: When creating an object via a constructor involves too many arguments or complex logic.
- Improve Performance: Cloning an existing object is faster and less resource-intensive than creating a new one from scratch.
- When to Use It?
- When new objects differ slightly from existing ones.
- When the system needs to generate many similar objects dynamically.
- When working with frameworks that require object cloning for performance (e.g., in caching or simulation systems).
We can use the Prototype Design Pattern when creating a new object is expensive (e.g., interacting with various resources like database connections, file systems, or external APIs). Additionally, it is useful when a new object has only slight differences from an existing object (e.g., a car object with engine v2, color red, and 4 wheels, and the new car object has engine v3 but retains other properties).
- Prototype Interface or Abstract Class
- This defines the method for cloning objects and sets a standard that all concrete prototypes must follow. Its main purpose is to serve as a blueprint for creating new objects by outlining the cloning contract.
- It includes a clone method that concrete prototypes will implement to create copies of themselves.
- Concrete Prototype
- This class implements the prototype interface or extends the abstract class. It represents a specific type of object that can be cloned.
- The Concrete Prototype details how the cloning process should work for instances of that class and provides the specific logic for the clone method.
- Client
- The Client is the code or module that requests new object creation by interacting with the prototype.
- It initiates the cloning process without needing to know the specifics of the concrete classes involved.
- Clone Method
- This method is declared in the prototype interface or abstract class and outlines how an object should be copied.
- Concrete prototypes implement this method to define their specific cloning behavior, detailing how to duplicate the object’s internal state to create a new, independent instance.
The principle method in the Prototype pattern is the clone() method, which is used to create a duplicate of the existing object.
// Step 1: Prototype Interface
interface Prototype {
Prototype clone();
public void setEngine(CarEngine carEngine);
public void setModel(int model);
}
class CarEngine {
public CarEngine() {}
public CarEngine(CarEngine carEngine) {
// Write logic here to copy the object
System.out.println("Copy Constructor Called");
}
}
// Step 2: Base Class for Cars
abstract class Car implements Prototype {
String color;
int wheels;
int velocity;
public Car(String color, int wheels, int velocity) {
this.color = color;
this.wheels = wheels;
this.velocity = velocity;
}
// Implement clone method
@Override
public abstract Car clone();
// Implement setEngine method
@Override
public abstract void setEngine(CarEngine carEngine);
// Implement setModel method
@Override
public abstract void setModel(int model);
}
// Step 3: RaceCar Class
class RaceCar extends Car {
int model;
CarEngine carEngine;
int speed;
public RaceCar() {
super("RED", 4, 100);
this.model = 2020;
this.carEngine = new CarEngine();
this.speed = 200;
}
private RaceCar(CarEngine carEngine, int model) {
super("RED", 4, 100);
this.model = model;
this.carEngine = new CarEngine(carEngine); // Deep Copy - Copy Construtor
}
@Override
public RaceCar clone() {
return new RaceCar(this.carEngine, this.model);
}
@Override
public void setEngine(CarEngine carEngine) {
this.carEngine = carEngine;
}
@Override
public void setModel(int model) {
this.model = model;
}
}
// Step 3: VintageCar Class
class VintageCar extends Car {
int model;
CarEngine carEngine;
public VintageCar() {
super("BLUE", 4, 200);
this.model = 2024;
this.carEngine = new CarEngine();
}
private VintageCar(CarEngine carEngine, int model) {
super("BLUE", 4, 200);
this.model = model;
this.carEngine = new CarEngine(carEngine);
}
@Override
public VintageCar clone() {
return new VintageCar(this.carEngine, this.model);
}
@Override
public void setEngine(CarEngine carEngine) {
this.carEngine = carEngine;
}
@Override
public void setModel(int model) {
this.model = model;
}
}
// Step 4: Client Code
public class PrototypePatternClient {
public static void main(String[] args) {
RaceCar raceCar = new RaceCar();
VintageCar vintageCar = new VintageCar();
RaceCar clonedRaceCar = raceCar.clone();
VintageCar clonedVintageCar = vintageCar.clone();
System.out.println(clonedRaceCar.model); // 2020
System.out.println(clonedVintageCar.model); // 2024
// We can change the properties of cloned objects
clonedRaceCar.setEngine(new CarEngine());
clonedRaceCar.setModel(2021);
clonedVintageCar.setEngine(new CarEngine());
clonedVintageCar.setModel(2025);
System.out.println(clonedRaceCar.model); // 2021
System.out.println(clonedVintageCar.model); // 2025
}
}
- Game Development: Cloning similar objects like enemies, weapons, or levels.
- Document Templates: Cloning a template to create a new document with predefined settings.
- Creating multiple similar objects in games or simulations.
- Duplicating complex objects like database connections, where creating new instances is resource-intensive.
1. Reduces the cost of object creation.
2. Allows dynamic creation of objects at runtime.
3. Simplifies object creation in dynamic scenarios.
1. Requires knowledge of cloning (e.g., clone() method).
2. Cloning may lead to issues with mutable objects.
3. May become complex with deep copy for nested objects.