Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.
It allows you to clone (even complex) objects without coupling to their specific classes.
You should use the Prototype pattern in the following cases :
- Whenever creation of new object requires setting many parameters and some (or all) are optional.
- To avoid building a class hierarchy of factories.
- When instances of a class can only have a few different states.
- When the class to instantiate are specified at run-time (dynamic loading)
Participants
- Prototype : Defines an interface to clone itself.
- ConcretePrototype : Implement the interface of Prototype.
- Client : Creates new objects by asking a Prototype to clone itself.
How to implement
- Create the Prototype interface (with the clone() method).
- Create the ConcretePrototypes that implement the Prototype interface to copy() themselves.
- Optionally, Add a registry
- It is easy to define a Registry using the Factory template that will store a catalog of frequently used prototype.
- As the client ask for a Prototype (based on any search criteria such as a enum or a combination of params...), the Registry will find it in its catalog and retrieve a copy() of it.
- This will simplify the management of the different possible prototypes as well as provide a unique point of creation.
Note : UML class diagram taken from here
Pros
- Readability : Produce complex objects more conveniently. You will also get rid of repeated initialization code in favor of cloning pre-built prototypes.
- Reducing subclassing
- Dynamically configure an application
Cons
- Implementing the clone() operation can be difficult when object structures contain circular references.
- Shallow copy vs deep copy problem : Should the clone() operation make a copy of the object parameters or should the original and clone share the parameters ?
- Initializing clones : The client might want to initialize some of the internal states of its clone. But you cannot pass those as parameters to your clone() operation (because their numbers will vary between prototypes). The client might have to use setters (if you provided them) just after the clone() operation or you might need to provide him with a initialize() operation.
The Prototype pattern is available in C++ with a Cloneable interface.
Here are some usefull ressources :
- A Refactoring guru article.
- A complete example here
