We're working on a substantial update for the whole design patterns section that should be ready by the end of September. Until then, please sorry for all embarrassing typos and errors you might encounter here and there.
Prototype is a creational design pattern that lets you produce new objects by copying existing ones without compromising their internals.
You have an object and want to create a duplicate. How would you do it? First, you need to create a fresh object of the same class. Then you have to go over through all fields of the original object and copy their values to the new object.
Nice! But there is a catch. Not all objects can be copied this way. Some of the objects can have private fields not accessible from the outside.
There is one more problem with this approach. Since you have to know object's class to be able to go over all its fields, your code will become dependent on the classes of objects that you copy. You will not be able to copy objects if you only know their interfaces, but not the actual classes.
The Prototype pattern delegates cloning process to objects themselves.
It declares the common interface for all objects that allow cloning. It allows cloning objects without tight coupling to their concrete classes. Usually, the prototype interface contains a single
The implementation of
clone method is similar for all classes. The method creates an object of a current class and copies all its field values into the new object. Most of the programming languages allow accessing private fields in an object of the same class, so the copying process is straightforward.
Objects that can be cloned are called prototypes. Sometimes, especially when your objects have a ton of fields and hundreds of possible configurations, prototypes can serve as an alternative to subclassing. In this case, the program creates a bunch of prototypes beforehand and then clones them instead of reconstructing objects from scratch.
Industry vs Cell Division
In real life, prototypes are used for performing various tests before starting the mass production of a product. However, in this case, prototypes do not participate in the actual production, playing a passive role.
Since industrial prototypes do not copy themselves, the much closer analogy of the pattern is mitotic cell division (biology, remember?). After such division, two completely identical cells are formed. The original cell acts as a prototype and takes an active role in creating a copy.
Prototype registry implementation
Prototype declares the cloning interface. In most cases, a single
clonemethod will be enough.
Concrete prototype implements the cloning method. In addition to straightforward copying field values to a fresh clone, this method may solve some caveats, which should remain hidden for Clients. For example, cloning linked objects, untangling recursive dependencies, etc.
Client uses the Prototype interface to retrieve an object's clone.
Prototype registry provides easy access to frequently used prototypes, storing a pre-created set of objects, ready to be copied. Usually, it can be implemented with a simple
name → prototypehash map. But for convenience, any other search criteria can be added to the registry.
In this example, the Prototype is used for cloning objects that represent geometric shapes without coupling to their classes.
All shape classes implement the common cloning interface with a single cloning method. Subclasses call the parent cloning method and then copy their own fields to the resulting object.
Therefore, the Prototype design pattern allows client code to clone objects, even without knowing and independent of their specific classes.
When your code should not depend on the concrete classes of objects that you need to copy. For examples, when objects' classes are unknown since you work with them via an interface.
The Prototype pattern provides a client an interface to work with all prototypes. This interface is common for all objects that support cloning. It makes client code independent from concrete classes of products that it clones.
When you want to reduce the size of a class hierarchy that consists of similar objects, configured in different ways (in other words, each class would have unique field values).
The Prototype pattern allows creating a set of prototype objects that represent all possible configurations of an object.
Then, instead of instantiating a subclass that matches some configuration, client code looks for the appropriate prototype and clones it.
How to Implement
Create the prototype interface and declare the
clonemethod in it. You may simply add the method to all classes of existing class hierarchy, if you have one.
Add an alternative constructor to all prototype classes, which accepts an object of a current class. The constructor must copy values of all fields defined in the class from the passed object to the current instance. Then it should call the parent constructor to take care of superclass fields.
If your programming language does not support method overloading, you may define a special method for copying the data. The constructor is just more convenient since it delivers the copy right after using the
clonemethod usually consists of just one line: running a
newoperator using the prototype constructor. Note, that each class that supports cloning must explicitly override the
clonemethod to use its class name along the
newoperator. Otherwise, cloning will produce an object of a parent class.
Optionally, create a centralized prototype registry to store the catalog of frequently used prototypes. It may even store objects of the same class, configured in different ways.
You can implement the registry as a new factory class or a factory method inside the base prototype class. The factory method should search for appropriate prototype based on the description that client code passes as an argument. It could be either just a string tag or a complex set of search criteria. After appropriate prototype had been found, it should clone it and return the copy to the client.
The last step would be eliminating direct calls to object constructors in favor of calls to the factory method of prototype registry.
Pros and Cons
- Allows cloning objects without coupling to their concrete classes.
- Reduces repeating initialization code.
- Creates complex objects faster.
- Provides an alternative for subclassing when you are dealing with complex objects having lots of configuration options.
- Complex objects with lots of references to other objects can be difficult to clone.
Relations with Other Patterns
Often, designs start out using Factory Method (less complicated, more customizable via subclasses) and evolve toward Abstract Factory, Prototype, or Builder (more flexible, but more complex) as the designer discovers where more flexibility is needed.
Prototype can be the simpler alternative to the Memento, if the object, which state you want to store in history, is fairly straightforward, doesn't have links to external resources, or if the links are easy to re-establish.