The prototype design pattern is a creational design pattern that involves creating objects by cloning them from existing ones. Its purpose is related to performance as creating an object from scratch may be more expensive then copying an existing object and modifying it.
There are two approaches in java to clone an object the first approach is using the java Cloneable interface and the second approach is using copy constructor. A fine approach to object copying is to provide a copy constructor considering the shortcomings of the clone in java . Below is paragraph from effective java on the shortcomings of clone in java
Given all of the problems associated with Cloneable, it’s safe to say that other interfaces should not extend it, and that classes designed for inheritance should not implement it. Because of its many shortcomings, some expert programmers simply choose never to override the clone method and never to invoke it except, perhaps, to copy arrays. If you design a class for inheritance, be aware that if you choose not to provide a well-behaved protected clone method, it will be impossible for subclasses to implement Cloneable.
Lets say we have an alert object which we need to clone for further analyses without effecting the actual alert object. As the alert object is composed of list in order for the clone method on Alert to work properly, it must copy the internals of the List and we are doing the same in below code for both approaches.
public class Alert implements Cloneable { private int subElementId; private int metricMetadataId; private int metricMetadataHourlyId; private float metricValue; private List<Integer> elementsEffected; public Alert(int subElementId, int metricMetadataId, int metricMetadataHourlyId, float metricValue, List<Integer> elementsEffected) { super(); this.subElementId = subElementId; this.metricMetadataId = metricMetadataId; this.metricMetadataHourlyId = metricMetadataHourlyId; this.metricValue = metricValue; this.elementsEffected = elementsEffected; } // Copy constructor approach public Alert(Alert alertCopy) { this.subElementId = alertCopy.subElementId; this.metricMetadataId = alertCopy.metricMetadataId; this.metricMetadataHourlyId = alertCopy.metricMetadataHourlyId; this.metricValue = alertCopy.metricValue; this.elementsEffected = new ArrayList<Integer>(alertCopy.elementsEffected); } // clone approach @Override public Alert clone() { Alert alert = null; try { alert = (Alert) super.clone(); alert.elementsEffected = new ArrayList<Integer>(this.elementsEffected); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return alert; } public int getSubElementId() { return subElementId; } public void setSubElementId(int subElementId) { this.subElementId = subElementId; } public int getMetricMetadataId() { return metricMetadataId; } public void setMetricMetadataId(int metricMetadataId) { this.metricMetadataId = metricMetadataId; } public int getMetricMetadataHourlyId() { return metricMetadataHourlyId; } public void setMetricMetadataHourlyId(int metricMetadataHourlyId) { this.metricMetadataHourlyId = metricMetadataHourlyId; } public float getMetricValue() { return metricValue; } public void setMetricValue(float metricValue) { this.metricValue = metricValue; } @Override public String toString() { return "Alert [subElementId=" + subElementId + ", metricMetadataId=" + metricMetadataId + ", metricMetadataHourlyId=" + metricMetadataHourlyId + ", metricValue=" + metricValue + ", elementsEffected=" + elementsEffected + "]"; } public List<Integer> getElementsEffected() { return elementsEffected; } public void setElementsEffected(List<Integer> elementsEffected) { this.elementsEffected = elementsEffected; } }