Prototype pattern
Prototype pattern overview
It is one of the creational design patterns in Java as it is used to create an object.
This pattern helps in creating objects based on the template of an existing object using cloning.
Instead of creating an object from scratch each and every time, we can create the copies of original object.
We can use the copied object and modify it as and when required.
This pattern is already used by java in Cloneable interface.
Cloneable interface acts as a marker interface to indicate what objects are eligible for cloning
Object class has already provided a definition for clone () method and any class in java can use it or it can override this clone () method to provide its own implementation.
The prototype design pattern mandates that the class(whose objects needs to be created again and again) should provide the copying feature.
It should not be done by an external utility class.
While implementing this pattern, we may use clone method provided by Java,
But decide based on requirement whether we need to use shallow cloning or deep cloning and implement clone() method of your own accordingly.
Let’s see the Pattern implementation
Step 1
First define a prototype interface by declaring a clone method
This is actually called as “Prototype”
Step 2
Define the multiple concrete prototype classes which implements the “Prototype” interface and define the clone() method as per the need
Step 3
Add all the prototypes to a prototype registry
Step 4
Let the client use the registry to access prototype instances
Requirement :
Create Permanent Employee and Contract employee instances based on the input passed and create these objects just by cloning as its creation is costly process.
Detailed Solution for the above requirement
Step 1
First define a prototype interface by declaring a clone method
- Public interface Employee{
- String name;
- String empId;
- Float salary;
- Employee clone();
- }
Public interface Employee{ String name; String empId; Float salary; Employee clone(); }
Step 2
Define multiple concrete prototype classes which implements the “Prototype” interface and define the clone() method as per the need
- Public class PermanentEmployee implements Employee{
- float bonus;
- public Employee clone(){
- Employee e = new PermanentEmployee();
- e.name="John";
- e.empId="p10001";
- e.salary=24500.50f;
- e.bonus=10250.50f;
- return e;
- }
- @Override
- public String toString() {
- return empId;
- }
- }
Public class PermanentEmployee implements Employee{ float bonus; public Employee clone(){ Employee e = new PermanentEmployee(); e.name="John"; e.empId="p10001"; e.salary=24500.50f; e.bonus=10250.50f; return e; } @Override public String toString() { return empId; } }
- Public class ContractorEmployee implements Employee{
- int contractYears;
- public Employee clone(){
- Employee e = new ContractorEmployee();
- e.name="Peter";
- e.empId="c10001";
- e.salary=18500.50f;
- e. contractYears =2;
- return e;
- }
- @Override
- public String toString() {
- return empId;
- }
- }
Public class ContractorEmployee implements Employee{ int contractYears; public Employee clone(){ Employee e = new ContractorEmployee(); e.name="Peter"; e.empId="c10001"; e.salary=18500.50f; e. contractYears =2; return e; } @Override public String toString() { return empId; } }
Step 3
Add all the prototypes to a prototype registry
- Public class EmployeeRegistry{
- Private static Map<String,Employee> prototypes = new HashMap<>();
- Static{
- prototypes.put("pEmp",new PermanentEmployee());
- prototypes.put("cEmp",new ContractorEmployee());
- }
- Public Employee getEmployee(String type){
- try{
- return prototypes.get(type).clone();
- }
- catch (NullPointerException e) {
- System.out.println("Prototype with name: " + type + ", doesn't exist");
- return null;
- }
- } //close of method
- } //close of class
Public class EmployeeRegistry{ Private static Map<String,Employee> prototypes = new HashMap<>(); Static{ prototypes.put("pEmp",new PermanentEmployee()); prototypes.put("cEmp",new ContractorEmployee()); } Public Employee getEmployee(String type){ try{ return prototypes.get(type).clone(); } catch (NullPointerException e) { System.out.println("Prototype with name: " + type + ", doesn't exist"); return null; } } //close of method } //close of class
Step 4
Let the client use the registry to access prototype instances
- public class PrototypePatternClient
- {
- public static void main(String[] args)
- {
- Employee pEmp = EmployeeRegistry.getEmployee("pEmp");
- System.out.println(pEmp);
- Employee cEmp = EmployeeRegistry.getEmployee("cEmp");
- System.out.println(cEmp);
- //Modify the cloned object as per need
- Employee cEmp1 = EmployeeRegistry.getEmployee("cEmp");
- cEmp1.contractYears=3;
- //Modify any other fields if required for new object
- }
- }
public class PrototypePatternClient { public static void main(String[] args) { Employee pEmp = EmployeeRegistry.getEmployee("pEmp"); System.out.println(pEmp); Employee cEmp = EmployeeRegistry.getEmployee("cEmp"); System.out.println(cEmp); //Modify the cloned object as per need Employee cEmp1 = EmployeeRegistry.getEmployee("cEmp"); cEmp1.contractYears=3; //Modify any other fields if required for new object } }
When to use this pattern?
When creating an object is a costly and time-consuming operation and, in that case, copying an object would be easier.
New objects required are almost similar to the existing objects.
Note:
We should always have good knowledge about the data of the object that is to be cloned and also make sure that cloned instance allows us to make changes to the data. If not, after cloning we will not be able to make required changes to the cloned object to get the object as per the need.