Prototype Pattern
Intent:
Create new objects by copying (cloning) an existing object, rather than creating from scratch.
When to Use:
When object creation is costly or complex, and you want to avoid creating new instances from scratch.
Key Characteristics:
- Cloning instead of instantiation
- Supports deep or shallow copy
- Useful for performance optimization
Example (PUBG Game: Bullets):
# bullet.py import copy class Bullet: def __init__(self, weapon_type, damage, speed, coordinates): self.weapon_type = weapon_type self.damage = damage self.speed = speed self.coordinates = coordinates # (x, y, z) def clone(self): return copy.deepcopy(self) def set_coordinates(self, coordinates): self.coordinates = coordinates def __str__(self): return f"Bullet({self.weapon_type}, Damage: {self.damage}, Speed: {self.speed}, Coordinates: {self.coordinates})"# bullet.py import copy class Bullet: def __init__(self, weapon_type, damage, speed, coordinates): self.weapon_type = weapon_type self.damage = damage self.speed = speed self.coordinates = coordinates # (x, y, z) def clone(self): return copy.deepcopy(self) def set_coordinates(self, coordinates): self.coordinates = coordinates def __str__(self): return f"Bullet({self.weapon_type}, Damage: {self.damage}, Speed: {self.speed}, Coordinates: {self.coordinates})"
# bullet_prototype_manager.py class BulletPrototypeManager: def __init__(self): self._prototypes = {} def register_prototype(self, name, bullet_prototype): self._prototypes[name] = bullet_prototype def unregister_prototype(self, name): if name in self._prototypes: del self._prototypes[name] def clone(self, name, new_coordinates): bullet = self._prototypes.get(name) if not bullet: raise ValueError(f"No prototype registered under name '{name}'") cloned = bullet.clone() cloned.set_coordinates(new_coordinates) return cloned# bullet_prototype_manager.py class BulletPrototypeManager: def __init__(self): self._prototypes = {} def register_prototype(self, name, bullet_prototype): self._prototypes[name] = bullet_prototype def unregister_prototype(self, name): if name in self._prototypes: del self._prototypes[name] def clone(self, name, new_coordinates): bullet = self._prototypes.get(name) if not bullet: raise ValueError(f"No prototype registered under name '{name}'") cloned = bullet.clone() cloned.set_coordinates(new_coordinates) return cloned
# main.py from bullet import Bullet from bullet_prototype_manager import BulletPrototypeManager if __name__ == "__main__": manager = BulletPrototypeManager() # Register base bullets akm_bullet = Bullet("AKM", damage=50, speed=900, coordinates=(0, 0, 0)) m416_bullet = Bullet("M416", damage=43, speed=880, coordinates=(0, 0, 0)) manager.register_prototype("AKM", akm_bullet) manager.register_prototype("M416", m416_bullet) # Fire bullets (clone with new coordinates) fired1 = manager.clone("AKM", (10, 5, 2)) fired2 = manager.clone("AKM", (12, 6, 2)) fired3 = manager.clone("M416", (8, 3, 1)) print(fired1) print(fired2) print(fired3)# main.py from bullet import Bullet from bullet_prototype_manager import BulletPrototypeManager if __name__ == "__main__": manager = BulletPrototypeManager() # Register base bullets akm_bullet = Bullet("AKM", damage=50, speed=900, coordinates=(0, 0, 0)) m416_bullet = Bullet("M416", damage=43, speed=880, coordinates=(0, 0, 0)) manager.register_prototype("AKM", akm_bullet) manager.register_prototype("M416", m416_bullet) # Fire bullets (clone with new coordinates) fired1 = manager.clone("AKM", (10, 5, 2)) fired2 = manager.clone("AKM", (12, 6, 2)) fired3 = manager.clone("M416", (8, 3, 1)) print(fired1) print(fired2) print(fired3)
Output:
Bullet(AKM, Damage: 50, Speed: 900, Coordinates: (10, 5, 2)) Bullet(AKM, Damage: 50, Speed: 900, Coordinates: (12, 6, 2)) Bullet(M416, Damage: 43, Speed: 880, Coordinates: (8, 3, 1))
Summary:
- Avoids expensive object creation by cloning prototypes.
- Ideal for high-frequency or performance-critical object usage (e.g., bullets, particles, enemies in games).
- Ensures consistent configuration and fast instantiation.
- Reduces code duplication and supports flexible object creation.
m416_bullet = Bullet("M416", damage=43, speed=880, coordinates=(0, 0, 0)) manager.register_prototype("AKM", akm_bullet) manager.register_prototype("M416", m416_bullet) **Fire bullets (clone with new coordinates)** fired1 = manager.clone("AKM", (10, 5, 2)) fired2 = manager.clone("AKM", (12, 6, 2)) fired3 = manager.clone("M416", (8, 3, 1)) print(fired1) print(fired2) print(fired3)
Output
Bullet(AKM, Damage: 50, Speed: 900, Coordinates: (10, 5, 2)) Bullet(AKM, Damage: 50, Speed: 900, Coordinates: (12, 6, 2)) Bullet(M416, Damage: 43, Speed: 880, Coordinates: (8, 3, 1))Bullet(AKM, Damage: 50, Speed: 900, Coordinates: (10, 5, 2)) Bullet(AKM, Damage: 50, Speed: 900, Coordinates: (12, 6, 2)) Bullet(M416, Damage: 43, Speed: 880, Coordinates: (8, 3, 1))
Summary
- Prototype Pattern avoids expensive object creation.
- Ideal for high-frequency object usage like game entities (bullets, particles, enemies).
- Ensures performance optimization and consistent object configuration.