This tutorial explain the basic concept of prototype design pattern and how to use them. This is one of the pattern I have published as part of our Design pattern in Java series. If you are interested in receiving updates, please subscribe our newsletter.
Prototype pattern is one of the creational patterns that concentrate on duplicating objects if needed. Assuming that we are in process of creating a template. Most of the times, we copy an existing template, do some changes in it and then will use it. Technically, we make a copy of the source, make some changes and will use according to the requirements. This is the core concept of the prototype pattern.
Additional Reading:
Prototype Design Pattern
For example, assuming that we are creating an Online Leave Application, where someone is asked to fill-in the reason for the leave, start and end date of his/her leave along with details of the approver. A smart thing is for the very first time, we can ask the person to fill in the details and for the subsequent time we can provide an option to copy the first template, do some changes (like changing the start and end date) and allow him to submit.
- One important thing that has to be considered in designing prototype design pattern is regarding the depth to which we want the object to be copied.
- In Java terms, whether we want shallow copying or deep copying. In shallow copying, only the primitive properties of the outer object will be copied during the cloning operation, and not the object references.
- It means that changes made to the target object will be reflected back to the original source object.
- Whereas, in the case of deep copying, all the primitive and the object references will be copied bit-by-bit, so that it can be ensured that changes done to the target object is not reflected back to the source.
Now, let us see an example for the Prototype pattern what we have discussed till now. Given below is the complete example,
LeaveApplication.java
import java.text.SimpleDateFormat; import java.util.Date; public class LeaveApplication implements Cloneable { private String reason; private Date startDate; private Date endDate; private Approver approver; public LeaveApplication( String reason, Date startDate, Date endDate, Approver approver){ this.reason = reason; this.startDate = startDate; this.endDate = endDate; this.approver = approver; } public LeaveApplication clone(){ Approver copyApprover = new Approver( approver.getName(), approver.getDesignation()); LeaveApplication copyApplication = new LeaveApplication( reason, ((Date)startDate.clone()), ((Date)endDate.clone()), copyApprover); return copyApplication; } public String toString(){ return "[Leave Application:" + reason + "," + toString(startDate) + "," + toString(endDate) + approver + "]"; } private String toString(Date date){ SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yy"); return format.format(date); } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } public Date getStartDate() { return startDate; } public void setStartDate(Date startDate) { this.startDate = startDate; } public Date getEndDate() { return endDate; } public void setEndDate(Date endDate) { this.endDate = endDate; } public Approver getApprover() { return approver; } public void setApprover(Approver approver) { this.approver = approver; } }
This LeaveApplication
is the class that we want to clone. It has 3 simple properties namely reason
, startDate
and endDate
and 1 composite property called Approver
. Later on we see the class definition for Approver
class. Now, let us have a look over the clone()
method. Within this method, we create a new instance for the LeaveApplication
class and set its properties to the value of the properties of the original object. In this way, we are making a deep cloning of the object and not a shallow cloning. Given below is the class definition for the Approver
class,
Approver.java
package tips.pattern.prototype; public class Approver { private String name; private String designation; public Approver(String name, String designation){ this.name = name; this.designation = designation; } public String toString(){ return "[Approver: " + name + "," + designation + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesignation() { return designation; } public void setDesignation(String designation) { this.designation = designation; } }
Then, we define the main class PrototypeTest
for testing the prototype pattern. It creates a new instance of the LeaveApplication
class for setting the sickLeave properties. After that, it makes a clone of the sickLeave
instance as a casualLeave
and modifies some of its properties like the reason and the dates.
PrototypeTest.java
package tips.pattern.prototype; import java.util.Date; public class PrototypeTest { public static void main(String[] args) { Approver manager = new Approver("Johny", "manager"); LeaveApplication sickLeave = new LeaveApplication("Fever", new Date(2007, 3, 20), new Date(2007, 3, 22), manager); System.out.println(sickLeave); LeaveApplication casualLeave = sickLeave.clone(); casualLeave.setReason("Vacation"); casualLeave.setStartDate(new Date(2007, 10, 10)); casualLeave.setEndDate(new Date(2007, 10, 20)); System.out.println(casualLeave); } }