In this comprehensive article, we will explore various aspects of Prototype Design Pattern in Java. So, let’s get started.
What is Prototype Design Pattern in Java?
The Prototype Design Pattern is a creational design pattern in Java and other object-oriented programming languages. It aims to create new objects by copying or cloning existing instances, thereby allowing the creation of new objects with the same state as an existing object.
Types of Cloning in Java
There are two types of cloning in Java.
- Shallow Cloning
- Deep Cloning
Shallow Cloning
In this case, a new cloned object is created with the exact copies of the values present in the original object.If original object has a reference to another object, then here only the value of reference is copied not the referred object.
Let us take a very simple example. Let’s say we have a Employee object which has a Address object. Now when we clone the Employee object, we create a copy of the Employee object, but we don’t create the copy of Address Object.We create a copy of Address reference.
How to achieve Shallow cloning in Java
We need to do the following steps to achieve Shallow cloning.
- Our class must implement Cloneable interface.
- Override the clone method of Object class.
Java Code: Shallow cloning in Java
Let us look into the java code.
package com.design.prototype;
public class Employee implements Cloneable {
private Address address;
private String name;
private String id;
@Override
public Employee clone() throws CloneNotSupportedException {
return (Employee) super.clone();
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
package com.design.prototype;
public class Address {
private String street;
private String city;
private String state;
private String country;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
package com.design.prototype;
public class PrototypeClient {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
address.setStreet("Patia");
address.setCity("Bhubaneswar");
address.setState("Odisha");
address.setCountry("India");
Employee employee = new Employee();
employee.setName("Gyan");
employee.setId("Test1234");
employee.setAddress(address);
Employee clonedEmployee = employee.clone();
System.out.println("Are the employee objects same:" + (employee == clonedEmployee));
System.out.println("Are the employee address objects same:" + (employee.getAddress() == clonedEmployee.getAddress()));
}
}
Are the employee objects same:false
Are the employee address objects same:true
Deep Cloning
In case of deep cloning, not just the references, but also the referred objects are copied.Continuing our Employee example,in case of deep cloning,when we clone the Employee object, we will internally also clone the Address object.
Java Code: Deep Cloning in Java
Let us look into the java code for achieving deep cloning.
package com.design.prototype;
public class Employee implements Cloneable {
private Address address;
private String name;
private String id;
@Override
public Employee clone() throws CloneNotSupportedException {
Employee clonedEmployee = (Employee) super.clone();
Address clonedAdress = this.getAddress().clone();
clonedEmployee.setAddress(clonedAdress);
return clonedEmployee;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
package com.design.prototype;
public class Address implements Cloneable {
private String street;
private String city;
private String state;
private String country;
@Override
public Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
package com.design.prototype;
public class PrototypeClient {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address();
address.setStreet("Patia");
address.setCity("Bhubaneswar");
address.setState("Odisha");
address.setCountry("India");
Employee employee = new Employee();
employee.setName("Gyan");
employee.setId("Test1234");
employee.setAddress(address);
Employee clonedEmployee = employee.clone();
System.out.println("Are the employee objects same:" + (employee == clonedEmployee));
System.out.println("Are the employee address objects same:" + (employee.getAddress() == clonedEmployee.getAddress()));
}
}
Are the employee objects same:false
Are the employee address objects same:false
Using Serialization for Deep Cloning
We can serialize an object and then create copies of the original object by deserializing.
Please visit Serialization for more info.
Usage of Prototype Design Pattern in Java:
Here are some common scenarios where you might use the Prototype Design Pattern in Java:
- Database Initialization: Efficiently create objects with data from a database by cloning existing instances.
- Graphic Design: Clone shapes and graphical elements in graphic design applications for rapid design iteration.
- Game Development: Clone characters, enemies, and items in games to save resources during object creation.
- Caching and Resources: Clone frequently used objects to optimize caching and resource management.
- Configuration: Create configuration templates and clone them to generate instances with different settings.
- Document Generation: Prototype templates for generating various document types with diverse content.
- UI Components: Rapidly create UI components with predefined styles and layouts using cloning.
- Network Connections: Clone connection objects with established settings for efficient network operations.
- Resource-Intensive Objects: Clone objects to avoid costly resource-heavy initialization.
- Undo/Redo: Capture object states with snapshots for implementing undo and redo functionality.
Pros of Prototype Design Pattern in Java
The Prototype Design Pattern offers several benefits in Java :
- Reduced Object Creation Overhead: Creating new objects from scratch, especially if the creation process involves complex initialization or resource-intensive operations, can be costly in terms of time and resources. The Prototype pattern allows you to clone existing objects, reducing the overhead of object creation.
- Flexibility in Object Creation: Prototypes can serve as templates for creating different variations of objects. By changing the state of a cloned object, you can easily create new instances with different attributes, without needing to write new object creation code.
- Enhanced Performance: In scenarios where creating objects is expensive, using prototypes can significantly improve performance. Reusing existing objects and their states can lead to better application responsiveness and reduced memory consumption.
- Encapsulation of Object Creation Logic: The Prototype pattern encapsulates the object creation logic within the object itself, making it easier to manage and modify the creation process without affecting the client code.
Cons of Prototype Design Pattern in Java
While the Prototype Design Pattern offers various benefits, it also has some limitations and potential drawbacks in certain situations. Here are few cons of the Prototype Design Pattern in Java:
- Deep Copy Complexity: Cloning complex objects might require extra effort for deep copies, potentially causing code maintenance challenges due to nested object cloning.
- Immutable Object Limitation: The pattern may not suit immutable objects, causing unnecessary data duplication and memory inefficiency when cloning.
- Prototype Initialization: Complex initialization steps or dependencies can make ensuring proper prototype initialization for cloning challenging, leading to inconsistent behavior.
- Increased Memory Usage: While Prototype conserves memory by reusing states, it can increase memory usage when cloning prototypes with substantial shared data.
Conclusion: Prototype Design Pattern in Java
In this comprehensive article, we’ve delved into various aspects of the Prototype Design Pattern in Java.
We began by understanding the essence of the Prototype design pattern in Java, a creational design pattern that facilitates object creation through copying or cloning existing instances.
We explored two types of cloning: shallow cloning and deep cloning. Shallow cloning involves copying references to objects, while deep cloning goes a step further by cloning both references and the referred objects themselves. For better comprehension, we examined the implementation of both types of cloning using Java code examples.
Shallow cloning was exemplified through an Employee
and Address
scenario. The code illustrated how to use the Cloneable
interface and override the clone()
method to achieve shallow copying. However, this approach merely replicated references, not the referenced objects.
To achieve deep cloning, we revisited the same Employee
and Address
example. The code demonstrated how to achieve deep copying by cloning both the employee and address objects, thus ensuring complete replication of the object hierarchy.
Additionally, we explored an alternative method for deep cloning using serialization. Serialization involves converting an object’s state into bytes, which can be subsequently deserialized to create a new instance with the same state.
Furthermore, we discussed the practical usage of the Prototype Design Pattern in Java in various scenarios. From efficient database initialization and graphic design applications to game development and resource caching, the Prototype pattern offers versatile solutions. Whether generating diverse documents, creating UI components, managing network connections, or handling resource-intensive objects, the Prototype pattern shines in enhancing object creation, improving performance, and managing variations.
However, as with any design pattern, the Prototype pattern has its downsides. We highlighted challenges related to deep copy complexity, limited support for immutable objects, prototype initialization intricacies, and potential memory usage increase. These limitations should be carefully considered when deciding whether to employ the Prototype pattern in a particular context.
Must-Read Design Pattern Articles