Prototype Pattern
When creating an object is time consuming and a costly affair and you already have a most similar object instance in hand, then you go for prototype pattern. Instead of going through a time consuming process to create a complex object, just copy the existing similar object and modify it according to your needs.
Its a simple and straight forward design pattern. Nothing much hidden beneath it. If you don’t have much experience with enterprise grade huge application, you may not have experience in creating a complex / time consuming instance. All you might have done is use the new operator or inject and instantiate.
Prototype pattern may look similar to builder design pattern. There is a huge difference to it. If you remember, “the same construction process can create different representations” is the key in builder pattern. But not in the case of prototype pattern.
So, how to implement the prototype design pattern? You just have to copy the existing instance in hand. When you say copy in java, immediately cloning comes into picture. Thats why when you read about prototype pattern, all the literature invariably refers java cloning.
Simple way is, clone the existing instance in hand and then make the required update to the cloned instance so that you will get the object you need. Other way is, tweak the cloning method itself to suit your new object creation need. Therefore whenever you clone that object you will directly get the new object of desire without modifying the created object explicitly.
The prototype design pattern mandates that the instance which you are going to copy should provide the copying feature. It should not be done by an external utility or provider.
But the above, other way comes with a caution. If somebody who is not aware of your tweaking the clone business logic uses it, he will be in issue. Since what he has in hand is not the exact clone. You can go for a custom method which calls the clone internally and then modifies it according to the need. Which will be a better approach.
Always remember while using clone to copy, whether you need a shallow copy or deep copy. Decide based on your business needs. If you need a deep copy, you can use serialization as a hack to get the deep copy done. Using clone to copy is entirey a design decision while implementing the prototype design pattern. Clone is not a mandatory choice for prototype pattern.
In prototype pattern, you should always make sure that you are well knowledgeable about the data of the object that is to be cloned. Also make sure that instance allows you to make changes to the data. If not, after cloning you will not be able to make required changes to get the new required object.
Following sample java source code demonstrates the prototype pattern. I have a basic bike in hand with four gears. When I want to make a different object, an advance bike with six gears I copy the existing instance. Then make necessary modifications to the copied instance. Thus the prototype pattern is implemented. Example source code is just to demonstrate the design pattern, please don’t read too much out of it. I wanted to make things as simple as possible.
Sample Java Source Code for Prototype Design Pattern
class Bike implements Cloneable {
private int gears;
private String bikeType;
private String model;
public Bike() {
bikeType = "Standard";
model = "Leopard";
gears = 4;
}
public Bike clone() {
return new Bike();
}
public void makeAdvanced() {
bikeType = "Advanced";
model = "Jaguar";
gears = 6;
}
public String getModel(){
return model;
}
}
public class Workshop {
public Bike makeJaguar(Bike basicBike) {
basicBike.makeAdvanced();
return basicBike;
}
public static void main(String args[]){
Bike bike = new Bike();
Bike basicBike = bike.clone();
Workshop workShop = new Workshop();
Bike advancedBike = workShop.makeJaguar(basicBike);
System.out.println("Prototype Design Pattern: "+advancedBike.getModel());
}
}
Applicability & Examples
Use Prototype Pattern when a system should be independent of how its products are created, composed, and represented, and:
Classes to be instantiated are specified at run-time
Avoiding the creation of a factory hierarchy is needed
It is more convenient to copy an existing instance than to create a new one.
Example 1
In building stages for a game that uses a maze and different visual objects that the character encounters it is needed a quick method of generating the haze map using the same objects: wall, door, passage, room... The Prototype pattern is useful in this case because instead of hard coding (using new operation) the room, door, passage and wall objects that get instantiated, CreateMaze method will be parameterized by various prototypical room, door, wall and passage objects, so the composition of the map can be easily changed by replacing the prototypical objects with different ones.
The Client is the CreateMaze method and the ConcretePrototype classes will be the ones creating copies for different objects.
Example 2:
Suppose we are doing a sales analysis on a set of data from a database. Normally, we would copy the information from the database, encapsulate it into an object and do the analysis. But if another analysis is needed on the same set of data, reading the database again and creating a new object is not the best idea. If we are using the Prototype pattern then the object used in the first analysis will be cloned and used for the other analysis.
The Client is here one of the methods that process an object that encapsulates information from the database. The ConcretePrototype classes will be classes that, from the object created after extracting data from the database, will copy it into objects used for analysis.
Specific problems and implementation
Using a prototype manager
When the application uses a lot of prototypes that can be created and destroyed dynamically, a registry of available prototypes should be kept. This registry is called the prototype manager and it should implement operations for managing registered prototypes like registering a prototype under a certain key, searching for a prototype with a given key, removing one from the register, etc. The clients will use the interface of the prototype manager to handle prototypes at run-time and will ask for permission before using the Clone() method.
There is not much difference between an implementation of a prototype which uses a prototype manager and a factory method implemented using class registration mechanism. Maybe the only difference consists in the performance.
Implementing the Clone operation
A small discussion appears when talking about how deep or shallow a clone should be: a deep clone clones the instance variables in the cloning object while a shallow clone shares the instance variables between the clone and the original. Usually, a shallow clone is enough and very simple, but cloning complex prototypes should use deep clones so the clone and the original are independent, a deep clone needing its components to be the clones of the complex object’s components.
Initializing clones
There are cases when the internal states of a clone should be initialized after it is created. This happens because these values cannot be passed to the Clone() method, that uses an interface which would be destroyed if such parameters were used. In this case the initialization should be done by using setting and resetting operations of the prototype class or by using an initializing method that takes as parameters the values at which the clone’s internal states should be set.
Hot points
Prototype Manager – implemented usually as a hashtable keeping the object to clone. When use it, prototype become a factory method which uses cloning instead of instantiation.
Deep Clones vs. Shallow Clones – when we clone complex objects which contains other objects, we should take care how they are cloned. We can clone contained objects also (deep cloning) or we can the same reference for them, and to share them between cloned container objects.Initializing Internal States – there are certain situations when objects need to be initialized after they are created.
Its a simple and straight forward design pattern. Nothing much hidden beneath it. If you don’t have much experience with enterprise grade huge application, you may not have experience in creating a complex / time consuming instance. All you might have done is use the new operator or inject and instantiate.
Prototype pattern may look similar to builder design pattern. There is a huge difference to it. If you remember, “the same construction process can create different representations” is the key in builder pattern. But not in the case of prototype pattern.
So, how to implement the prototype design pattern? You just have to copy the existing instance in hand. When you say copy in java, immediately cloning comes into picture. Thats why when you read about prototype pattern, all the literature invariably refers java cloning.
Simple way is, clone the existing instance in hand and then make the required update to the cloned instance so that you will get the object you need. Other way is, tweak the cloning method itself to suit your new object creation need. Therefore whenever you clone that object you will directly get the new object of desire without modifying the created object explicitly.
The prototype design pattern mandates that the instance which you are going to copy should provide the copying feature. It should not be done by an external utility or provider.
But the above, other way comes with a caution. If somebody who is not aware of your tweaking the clone business logic uses it, he will be in issue. Since what he has in hand is not the exact clone. You can go for a custom method which calls the clone internally and then modifies it according to the need. Which will be a better approach.
Always remember while using clone to copy, whether you need a shallow copy or deep copy. Decide based on your business needs. If you need a deep copy, you can use serialization as a hack to get the deep copy done. Using clone to copy is entirey a design decision while implementing the prototype design pattern. Clone is not a mandatory choice for prototype pattern.
In prototype pattern, you should always make sure that you are well knowledgeable about the data of the object that is to be cloned. Also make sure that instance allows you to make changes to the data. If not, after cloning you will not be able to make required changes to get the new required object.
Following sample java source code demonstrates the prototype pattern. I have a basic bike in hand with four gears. When I want to make a different object, an advance bike with six gears I copy the existing instance. Then make necessary modifications to the copied instance. Thus the prototype pattern is implemented. Example source code is just to demonstrate the design pattern, please don’t read too much out of it. I wanted to make things as simple as possible.
Sample Java Source Code for Prototype Design Pattern
class Bike implements Cloneable {
private int gears;
private String bikeType;
private String model;
public Bike() {
bikeType = "Standard";
model = "Leopard";
gears = 4;
}
public Bike clone() {
return new Bike();
}
public void makeAdvanced() {
bikeType = "Advanced";
model = "Jaguar";
gears = 6;
}
public String getModel(){
return model;
}
}
public class Workshop {
public Bike makeJaguar(Bike basicBike) {
basicBike.makeAdvanced();
return basicBike;
}
public static void main(String args[]){
Bike bike = new Bike();
Bike basicBike = bike.clone();
Workshop workShop = new Workshop();
Bike advancedBike = workShop.makeJaguar(basicBike);
System.out.println("Prototype Design Pattern: "+advancedBike.getModel());
}
}
Applicability & Examples
Use Prototype Pattern when a system should be independent of how its products are created, composed, and represented, and:
Classes to be instantiated are specified at run-time
Avoiding the creation of a factory hierarchy is needed
It is more convenient to copy an existing instance than to create a new one.
Example 1
In building stages for a game that uses a maze and different visual objects that the character encounters it is needed a quick method of generating the haze map using the same objects: wall, door, passage, room... The Prototype pattern is useful in this case because instead of hard coding (using new operation) the room, door, passage and wall objects that get instantiated, CreateMaze method will be parameterized by various prototypical room, door, wall and passage objects, so the composition of the map can be easily changed by replacing the prototypical objects with different ones.
The Client is the CreateMaze method and the ConcretePrototype classes will be the ones creating copies for different objects.
Example 2:
Suppose we are doing a sales analysis on a set of data from a database. Normally, we would copy the information from the database, encapsulate it into an object and do the analysis. But if another analysis is needed on the same set of data, reading the database again and creating a new object is not the best idea. If we are using the Prototype pattern then the object used in the first analysis will be cloned and used for the other analysis.
The Client is here one of the methods that process an object that encapsulates information from the database. The ConcretePrototype classes will be classes that, from the object created after extracting data from the database, will copy it into objects used for analysis.
Specific problems and implementation
Using a prototype manager
When the application uses a lot of prototypes that can be created and destroyed dynamically, a registry of available prototypes should be kept. This registry is called the prototype manager and it should implement operations for managing registered prototypes like registering a prototype under a certain key, searching for a prototype with a given key, removing one from the register, etc. The clients will use the interface of the prototype manager to handle prototypes at run-time and will ask for permission before using the Clone() method.
There is not much difference between an implementation of a prototype which uses a prototype manager and a factory method implemented using class registration mechanism. Maybe the only difference consists in the performance.
Implementing the Clone operation
A small discussion appears when talking about how deep or shallow a clone should be: a deep clone clones the instance variables in the cloning object while a shallow clone shares the instance variables between the clone and the original. Usually, a shallow clone is enough and very simple, but cloning complex prototypes should use deep clones so the clone and the original are independent, a deep clone needing its components to be the clones of the complex object’s components.
Initializing clones
There are cases when the internal states of a clone should be initialized after it is created. This happens because these values cannot be passed to the Clone() method, that uses an interface which would be destroyed if such parameters were used. In this case the initialization should be done by using setting and resetting operations of the prototype class or by using an initializing method that takes as parameters the values at which the clone’s internal states should be set.
Hot points
Prototype Manager – implemented usually as a hashtable keeping the object to clone. When use it, prototype become a factory method which uses cloning instead of instantiation.
Deep Clones vs. Shallow Clones – when we clone complex objects which contains other objects, we should take care how they are cloned. We can clone contained objects also (deep cloning) or we can the same reference for them, and to share them between cloned container objects.Initializing Internal States – there are certain situations when objects need to be initialized after they are created.