-
PrototypeModeling/DesignPattern 2020. 2. 26. 00:41
1. Overview
We have a complex object that is costly to create. To create more instances of such class, we use an existing instance as our prototype. Prototype will allow us to make copies of the existing objects and save us from having to recreate objects from scratch.
2. Description
2.1 Implementation
- Prototype class must implement Cloneable interface
- Prototype Class should override the clone method and return a copy of itself
- The method should declare CloneNotSupportedException in throws clause to give subclasses chance to decide on whether to support cloning
- Clone method implementation should consider the deep and shallow copy and choose whichever is applicable
2.2 Consideration
2.2.1 Implementation
- Pay attention to the deep copy and shallow copy of references. Immutable fields on clones save the trouble of deep copy
- Make sure to reset the mutable state of an object before returning the prototype. It's a good idea to implement this in method to allow subclasses to initialize themselves
- clone() method is protected in Object class and must be overridden to be public to be callable from outside the class
- Cloneable is a "marker" interface, an indication that the class supports cloning
2.2.2 Design
- Porotypes are useful when you have large objects where the majority of the state is unchanged between instances and you can identify that state.
- A prototype registry is a class wherein you can register various prototypes that other code can access to clone out instances. This solves the issue of getting access to the initial instance.
- Prototypes are useful when working with Composite and Decorator patterns
2.3 Pitfalls
- Usability depends upon the number of properties in the state that are immutable or can be shallow copied. An object where the state is compromised of large number of mutable objects is complicated to clone
- In Java, the default clone operation will only perform the shallow copy so if you need a deep copy you've to implement it.
- Subclasses may not be to support clone and so the code becomes complicated as you have to code for situations where implementation may not support clone.
3. Usage
- Object.clone()
4. Comparison with Singleton
Prototype Singleton We return a copy of an instance We return same instance every time Some or even all of the state of instances created with prototypes can be different Since it's the same object that is returned sate is always the same 5. Example
abstract class GameUnit implements Cloneable { private Point3D position; public GameUnit() { position = Point3D.ZERO; } @Override public GameUnit clone() throws CloneNotSupportedException { GameUnit unit = (GameUnit)super.clone(); unit.initialize(); return unit; } protected void initialize() { this.position = Point3D.ZERO; reset(); } protected abstract void reset(); public GameUnit(float x, float y, float z) { position = new Point3D(x, y, z); } public void move(Point3D direction, float distance) { Point3D finalMove = direction.normalize(); finalMove = finalMove.multiply(distance); position = position.add(finalMove); } public Point3D getPosition() { return position; } } class General extends GameUnit{ private String state = "idle"; public void boostMorale() { this.state = "MoralBoost"; } @Override public String toString() { return "General "+state+" @ "+getPosition(); } @Override public GameUnit clone() throws CloneNotSupportedException { throw new CloneNotSupportedException("Ganerals are unique"); } @Override protected void reset() { throw new UnsupportedOperationException("Reset not supported"); } } class Swordsman extends GameUnit { private String state = "idle"; public void attack() { this.state = "attacking"; } @Override public String toString() { return "Swordsman "+state+" @ "+getPosition(); } @Override protected void reset() { state = "idle"; } } public class Client { public static void main(String[] args) throws CloneNotSupportedException { Swordsman s1 = new Swordsman(); s1.move(new Point3D(-10,0,0), 20); s1.attack(); Swordsman s2 = (Swordsman)s1.clone(); System.out.println(s1); System.out.println("Cloned swordsman"+s2); } }
6. Reference