Prototype Pattern
The Prototype is a creational design pattern that allows creating new objects by cloning existing ones, avoiding explicit constructors for complex initialization. It is ideal when object creation is expensive or when you want to copy pre-configured instances.
Key Principles
- Cloning: Create duplicates via prototype interface.
- Shallow vs Deep Copy: Shallow copies references; deep copies recursively.
- Prototype Registry: Central place to store and retrieve prototypes.
Structure
- Prototype Interface:
clone()method. - Concrete Prototype: Implements clone (e.g.,
copy.deepcopyin Python). - Client: Requests clones from registry or prototypes.
Python Example: Shape Prototypes
import copy
from typing import List
class Shape:
def __init__(self, color: str, thickness: int):
self.color = color
self.thickness = thickness
self.position = (0, 0)
def clone(self):
return copy.deepcopy(self) # Deep copy
def move(self, x: int, y: int):
self.position = (x, y)
def __str__(self):
return f"Shape(color={self.color}, thickness={self.thickness}, pos={self.position})"
# Concrete Prototypes
class Circle(Shape):
def __init__(self, radius: float, color: str = "black", thickness: int = 1):
super().__init__(color, thickness)
self.radius = radius
def clone(self):
return copy.deepcopy(self)
class Rectangle(Shape):
def __init__(self, width: float, height: float, color: str = "black", thickness: int = 1):
super().__init__(color, thickness)
self.width = width
self.height = height
def clone(self):
return copy.deepcopy(self)
# Prototype Registry
class ShapeRegistry:
def __init__(self):
self.prototypes = {}
def register(self, name: str, prototype: Shape):
self.prototypes[name] = prototype
def create(self, name: str) -> Shape:
if name in self.prototypes:
return self.prototypes[name].clone()
raise ValueError(f"No prototype registered for {name}")
# Usage (Client Code)
if __name__ == "__main__":
registry = ShapeRegistry()
# Register prototypes
registry.register("circle", Circle(radius=5, color="red"))
registry.register("rectangle", Rectangle(width=10, height=5, color="blue"))
# Create clones
cloned_circle = registry.create("circle")
cloned_circle.move(10, 20)
print(cloned_circle) # Shape(color=red, thickness=1, pos=(10, 20))
cloned_rect = registry.create("rectangle")
cloned_rect.move(5, 15)
print(cloned_rect) # Shape(color=blue, thickness=1, pos=(5, 15))
print(f"Original vs Clone: {registry.create('circle') is cloned_circle}") # False (new instance)
Output:
Shape(color=red, thickness=1, pos=(10, 20))
Shape(color=blue, thickness=1, pos=(5, 15))
Original vs Clone: False
When to Use Prototype
- Expensive Creation: Cloning is cheaper than new objects (e.g., loaded configs).
- Prototype Variations: Base object with customizations.
- Avoid: If objects are immutable or cloning is complex.
Summary: Prototype enables efficient object duplication by cloning pre-made instances, reducing creation overhead while maintaining flexibility.