Creational Pattern: Prototype
This article discusses how new objects can be created from existing objects using the prototype pattern.
What is it?
The Prototype pattern is a creational pattern in which new objects are created by copying an existing object. The object whose copies are made is called the prototype. To understand objects better, you can consider the prototype object to be the “seed” from which all other objects get created. So you might ask why wouldn’t you create new objects when needed instead of cloning existing ones. The motivations for prototype objects are as follows:
- Sometimes creating a new object is more expensive than copying an existing one.
- Imagine if you couldn’t access a class’s constructor statically, and the runtime environment had to create an instance of each dynamically loaded class. Instead, the application could request objects from a prototype manager who would return clones of prototypes.
- You can significantly reduce the number of classes in a system by varying the values of cloned objects from a prototypical instance.
You can define an object by describing how to make an instance of that object and then make copies of that instance to create other objects.
Class Diagram
The class diagram contains the following entities:
- Prototype
- Concrete Prototype
- Client
Example
Let’s take the example of an aircraft to understand the prototype pattern better. First, we created a class to represent the F-16. But we know that the F-16 has some variants. So to represent each of the variants of the F16, we can create subclasses. But then we’ll end up with several subclasses in our system. In addition, let’s suppose that the F16 variants differ only by their engine types. Then one possibility would be to retain a single F16 class but add a method to set the engine type of the aircraft. That way, we can create a single F16 object as a prototype and clone it for various aircraft versions.
First, we create an interface.
The F-16 class implements its interface like this:
The client can use the pattern like this:
Note that the clone method of the IAircraftPrototype interface returns an abstract type. Clients don’t know what different implementations of the same interface will create concrete subclasses. For example, the Boeing747 class can be passed in, producing copies of whatever prototype is passed in (an F16 or a Boeing747). The prototype pattern helps eliminate subclassing, as the behavior of prototype objects can be varied by composing them with subparts.
Shallow vs. Deep Copy
The prototype pattern requires the prototype class or interface to implement a clone() method. Cloning can be either shallow or deep. For example, if our F-16 class has a member object of type F16Engine, in a shallow copy, the cloned object would point to the same F16Engine object as the prototype. But in a deep copy, the cloned object would get its copy of its engine object and any objects nested inside it. There won’t be any sharing of any fields — nested or otherwise — between the prototype and its clone.
Dynamic Loading
The prototype pattern can make the dynamic loading of classes easier. Dynamic loading allows you to load a class at runtime instead of having the class available at compile time. In a language that supports dynamic loading, a framework will create an instance of the loaded class and register it in a managing entity. Then, at runtime, your application can ask this manager to give you an object that belongs to that class.
Other examples
In the Java programming language, the Object class has a clone method. The class implements interface java.lang.Cloneable.
Caveats
Implementing the clone method can be difficult because of circular references.
Other articles in the Creational Pattern series
- Creational Pattern: Singleton
- Creational Pattern: Builder
- Creational Pattern: Factory Method
- Creational Pattern: Abstract Factory
My other publications: https://ercindedeoglu.github.io/