Design Pattern Course
It is a type of Creational Design Pattern.
Prototype pattern is used when the Object creation is a costly affair and requires a lot of time and resources, and you already have a similar object available. So, this pattern provides a mechanism to copy the original object to a new object and then modify it according to our needs. In Java, this can be implemented using cloning or by creating a custom copy method.
It would be easy to understand this pattern with an example. Suppose we have an object that loads data from a database. Now we need to modify this data in our program multiple times, so it is not a good idea to create the object using the new keyword and load all the data again from the database. So, the better approach is to copy the existing object into a new object and then do the data manipulation.
Prototype design pattern mandates that the object which you are copying should provide the copying feature. It should not be done by any other class. However, whether to use shallow or deep copy of the object properties depends on the requirements, and it is a design decision.
One example of how this can be useful is if an original object is created with a resource such as a data stream that may not be available at the time that a copy of the object is needed. Another example is if the original object creation involves a significant time commitment, such as reading data from a database or over a network.
Normally in Java, if you'd like to use cloning (i.e., the prototype pattern), you can utilize the clone() method and the Cloneable interface. By default, clone() performs a shallow copy. However, many modern Java applications prefer custom copy methods because they are clearer and easier to control.
However, we can implement our own prototype pattern. To do so, we can create a class that provides a copy method.
package com.praveen.designpatterns.creational.prototype; import java.util.ArrayList; import java.util.List; public class LoanApplication { private String loanType; private String applicantName; private double amount; private List<String> documents; public LoanApplication() { documents = new ArrayList<>(); } public LoanApplication(String loanType, String applicantName, double amount, List<String> documents) { this.loanType = loanType; this.applicantName = applicantName; this.amount = amount; this.documents = new ArrayList<>(documents); } public LoanApplication clone() { return new LoanApplication(loanType, applicantName, amount, documents); } public String getLoanType() { return loanType; } public void setLoanType(String loanType) { this.loanType = loanType; } public String getApplicantName() { return applicantName; } public void setApplicantName(String applicantName) { this.applicantName = applicantName; } public double getAmount() { return amount; } public void setAmount(double amount) { this.amount = amount; } public List<String> getDocuments() { return documents; } public void setDocuments(List<String> documents) { this.documents = documents; } @Override public String toString() { return "LoanApplication [loanType=" + loanType + ", applicantName=" + applicantName + ", amount=" + amount + ", documents=" + documents + "]"; } }
package com.praveen.designpatterns.creational.prototype; import java.util.Arrays; public class ProtoTypeTest { public static void main(String[] args) { LoanApplication l1 = new LoanApplication("Home Loan", "Rahul", 2500000, Arrays.asList("PAN Card", "Aadhaar Card", "Salary Slips")); LoanApplication l2 = l1.clone(); l2.setApplicantName("Sneha"); l2.setAmount(3200000); l2.getDocuments().add("Bank Statement"); System.out.println(l1); System.out.println(l2); } }
Output
LoanApplication [loanType=Home Loan, applicantName=Rahul, amount=2500000.0, documents=[PAN Card, Aadhaar Card, Salary Slips]] LoanApplication [loanType=Home Loan, applicantName=Sneha, amount=3200000.0, documents=[PAN Card, Aadhaar Card, Salary Slips, Bank Statement]]
When to Use
- When the classes to instantiate are specified at run-time, for example, by dynamic loading; or
- To avoid building a class hierarchy of factories that parallels the class hierarchy of products; or
- When instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and copy them rather than instantiating the class manually each time with the appropriate state.
Prototype Design Pattern Example in JDK
- java.lang.Object#clone()