This chapter covers the prototype pattern.
GoF Definition
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
Concept
In general, creating a new instance from scratch is a costly operation. Using the prototype pattern, you can create new instances by copying or cloning an instance of an existing one. This approach saves both time and money in creating a new instance from scratch.
Real-World Example
Suppose we have a master copy of a valuable document. We need to incorporate some changes to it to see the effect of the change. In such a case, we can make a photocopy of the original document and edit the changes.
Consider another example. Suppose a group of people decide to celebrate the birthday of their friend Ron. They go to a bakery and buy a cake. To make it special, they request the seller to write, “Happy Birthday Ron” on the cake. From the seller’s point of view, he is not making any new model. He already defined the model and produces many cakes (which all look the same) every day by following the same process, and finally makes each special with some small changes.
Computer-World Example
Let’s assume that you have an application that is very stable. In the future, you may want to update the application with some small modifications. So, you start with a copy of your original application, make changes, and analyze further. Surely, to save your time and money, you do not want to start from scratch.
Note
Consider the Object.clone() method as an example of a prototype.
Illustration
Here, BasicCar is a basic prototype. Nano and Ford are the concrete prototypes that have implemented the clone() method defined in BasicCar. In this example, we have created a BasicCar class with a default price (in Indian currency). Later, we modify the price per model. PrototypePatternExample.java is the client in this implementation.
Class Diagram
Package Explorer View
Implementation
Output
Note
You can see a different price in your system because we are generating a random price in the setAdditionalPrice() method inside the BasicCar class. But I have assured that the price of the Ford will be greater than the Nano.
Q&A Session
- 1.What are the advantages of using prototype design patterns?
It is useful when creating an instance of a class is a complicated (or boring) process. Instead, you can focus on other key activities.
You can include or discard products at runtime.
You can create new instances at a cheaper cost.
- 2.What are the challenges associated with using prototype design patterns?
Each subclass needs to implement the cloning or copying mechanism.
Sometimes creating a copy from an existing instance is not simple. For example, implementing a cloning mechanism can be challenging if the objects under consideration do not support copying/cloning or if there are circular references. For example, in Java, a class with the clone() method needs to implement the Cloneable marker interface; otherwise, it will throw a CloneNotSupportedException.
In this example, I have used the clone() method that performs a shallow copy in Java. Following the convention, I obtained the returned object by calling super.clone().(If you want to learn more about this, put your cursor on the eclipse editor and go through the instructions). If you need a deep copy for your application, that can be expensive.
- 3.
Can you please elaborate the difference between a shallow copy and a deep copy?
A shallow copy creates a new object and then copies various field values from the original object to the new object. So, it is also known as a field-by-field copy . If the original object contains any references to other objects as fields, then the references of those objects are copied into the new object, (i.e., you do not create the copies of those objects).
Let’s try to understand the mechanism with a simple diagram. Suppose we have an object, X1, and it has a reference to another object, Y1. Further assume that object Y1 has a reference to object Z1.
You have already seen the use of the clone() method in our implementation. It performs a shallow copy.
- 4.
When do you choose a shallow copy over a deep copy (and vice versa)?
A shallow copy is faster and less expensive. It is always better if your target object has the primitive fields only.
A deep copy is expensive and slow. But it is useful if your target object contains many fields that have references to other objects.
- 5.
When I copy an object in Java, I need to use the clone() method. Is this understanding correct?
No. There are alternatives available, and one of them is to use the serialization mechanism. But you can always define your own copy constructor and use it.
- 6.
Can you give a simple example that demonstrates a user-defined copy constructor?
Java does not support a default copy constructor. You may need to write your own. Consider the following program, which demonstrates such a usage.