Prototype design pattern is one of the creational design patterns. This pattern clones the existing object instead of creating new one. The cloning could be deep cloning or shallow cloning depending upon the context of the problem.
Prototype design pattern is useful when the creation of an object is expensive and consuming lot of time and resource. In such cases, this pattern clones an already existing object and we could customize the cloned object as per our need.
Advantages
- When the creation of an object is expensive, time consuming and complex, this pattern takes care of creating such objects.
- Client need not to know how to create this complex object.
- State of a cloned object could be modified if needed.
Example
Tea-Coffee spot is the place where tea and coffee are made with pre-defined notes. When a client makes an order, the pre-defined note is cloned and given an order number. The client can make changes to the cloned order that is add more sugar or less sugar or no sugar. That is, the client has just cloned the tea/coffee and then customized it.
Example Diagram
Creating TeaCoffeeOrder Class
This class holds the responsibility of creating tea or coffee order based on the instructions provided by the client. This class implements cloneable interface and override the clone method to provide the clone object.
This class holds the core logic relevant to protype pattern.
package com.learningupskills.designpattern.prototype;
public class TeaCoffeeOrder implements Cloneable{
private BevarageType type;
private SugarLevel sugarLevel = SugarLevel.NORMALSUGAR;
private boolean isMilkBased = true;
private boolean isColdCofee;
private int orderNumber;
public TeaCoffeeOrder(String preparationNote, BevarageType type)
{
this.type = type;
}
public BevarageType getType() {
return type;
}
public void setType(BevarageType type) {
this.type = type;
}
public SugarLevel getSugarLevel() {
return sugarLevel;
}
public void setSugarLevel(SugarLevel sugarLevel) {
this.sugarLevel = sugarLevel;
}
public boolean isMilkBased() {
return isMilkBased;
}
public void setMilkBased(boolean isMilkBased) {
this.isMilkBased = isMilkBased;
}
public boolean isColdCofee() {
return isColdCofee;
}
public void setColdCofee(boolean isColdCofee) {
this.isColdCofee = isColdCofee;
}
public void printOrderDetails()
{
String isHotOrCold = this.isColdCofee?"Cold":"Hot";
String isMilkOrWater = this.isMilkBased?"With":"Without";
if(orderNumber ==0)
{
System.out.println("This is Original Object with below details:");
System.out.println(isHotOrCold+type.toString()+" "+isMilkOrWater+" Milk and with "+sugarLevel.toString());
}
else
{
System.out.println("This is Prototyped/Cloned Object with order Number :"+orderNumber);
System.out.println("You have ordered "+isHotOrCold+type.toString()+" "+isMilkOrWater+" Milk and with "+sugarLevel.toString());
}
}
private void generateOrder()
{
this.orderNumber =(int)(Math.random()*(10000-1000+1)+1000);
}
@Override
protected Object clone() throws CloneNotSupportedException {
this.generateOrder();
return super.clone();
}
}
Creating BevarageType enum
This enum represents different types of beverages such as coffee or tea
package com.learningupskills.designpattern.prototype;
public enum BevarageType {
TEA, COFFEE;
}
Creating SugarLevel enum
This enum represents different amount of sugar can be added to beverages such as NOSUGAR, LESSSUGAR, NORMALSUGAR.
package com.learningupskills.designpattern.prototype;
public enum SugarLevel {
NOSUGAR, LESSSUGAR, NORMALSUGAR, HIGHSUGAR;
}
Creating TeaShop Class
Teashop class is responsible for creating various tea and coffee combinations and stores as predefined notes.
Based on the order it fetches one of the predefined notes and makes the order by cloning.
Customization could be made such as less sugar, no sugar etc.
package com.learningupskills.designpattern.prototype;
import java.util.HashMap;
import java.util.Map;
public class TeaShop {
//Notes for Coffee preparation
private final static String HOT_MILKCOFFEE_WITH_NORMALSUGAR="HOT_MILKCOFFEE_WITH_NORMALSUGAR";
private final static String HOT_BLACKCOFFEE_WITH_NORMALSUGAR="HOT_BLACKCOFFEE_WITH_NORMALSUGAR";
private final static String COLD_MILKCOFFEE_WITH_NORMALSUGAR="COLD_MILKCOFFEE_WITH_NORMALSUGAR";
//Notes for Tea preparation
private final static String HOT_MILKTEA_WITH_NORMALSUGAR="HOT_MILKTEA_WITH_NORMALSUGAR";
private final static String HOT_BLACKTEA_WITH_NORMALSUGAR="HOT_BLACKTEA_WITH_NORMALSUGAR";
private final static String ICE_TEA_WITH_NORMALSUGAR="ICE_TEA_WITH_NORMALSUGAR";
private Map<String, TeaCoffeeOrder> similarOrders;
private String teaShopName;
public TeaShop(String teaShopName)
{
this.teaShopName = teaShopName;
this.similarOrders =new HashMap<String, TeaCoffeeOrder>();
this.prepopulatePreparationNote();
}
private void prepopulatePreparationNote()
{
//Pre populated coffee preparation note
orderTeaOrCoffe(TeaShop.HOT_MILKCOFFEE_WITH_NORMALSUGAR,true, true, SugarLevel.NORMALSUGAR, true);
orderTeaOrCoffe(TeaShop.HOT_BLACKCOFFEE_WITH_NORMALSUGAR,true, true, SugarLevel.NORMALSUGAR, false);
orderTeaOrCoffe(TeaShop.COLD_MILKCOFFEE_WITH_NORMALSUGAR,true, false, SugarLevel.NORMALSUGAR, true);
//Pre populated tea preparation note
orderTeaOrCoffe(TeaShop.HOT_MILKTEA_WITH_NORMALSUGAR,false, true, SugarLevel.NORMALSUGAR, true);
orderTeaOrCoffe(TeaShop.HOT_BLACKTEA_WITH_NORMALSUGAR,false, true, SugarLevel.NORMALSUGAR, false);
orderTeaOrCoffe(TeaShop.ICE_TEA_WITH_NORMALSUGAR,false, false, SugarLevel.NORMALSUGAR, false);
}
public String getTeaShopName() {
return teaShopName;
}
private TeaCoffeeOrder orderTeaOrCoffe(String preparationNote, boolean isCoffee, boolean isHot, SugarLevel level, boolean isMilkBased )
{
TeaCoffeeOrder order = new TeaCoffeeOrder(preparationNote, isCoffee?BevarageType.COFFEE:BevarageType.TEA);
order.setColdCofee(isHot);
order.setMilkBased(isMilkBased);
order.setSugarLevel(level);
similarOrders.put(preparationNote, order);
return order;
}
public static void main(String[] args) throws CloneNotSupportedException {
TeaShop shop = new TeaShop("SPSN Bhavan");
System.out.println("Tea Shop Name :"+shop.teaShopName);
System.out.println("*********************************************************************************");
//Original Note for ice tea with normal sugar
TeaCoffeeOrder note1 = shop.similarOrders.get(ICE_TEA_WITH_NORMALSUGAR);
note1.printOrderDetails();
System.out.println("---------------------------------------------------------------------------------");
//Order(Cloned) for for ice tea with normal sugar
TeaCoffeeOrder oreder1 = (TeaCoffeeOrder) note1.clone();
//Customized to less sugar
oreder1.setSugarLevel(SugarLevel.LESSSUGAR);
oreder1.printOrderDetails();
System.out.println("*********************************************************************************");
//Original Note for hot black coffee with normal sugar
TeaCoffeeOrder note2 = shop.similarOrders.get(HOT_BLACKCOFFEE_WITH_NORMALSUGAR);
note2.printOrderDetails();
System.out.println("---------------------------------------------------------------------------------");
//Order(Cloned) for hot black coffee with normal sugar
TeaCoffeeOrder oreder2 = (TeaCoffeeOrder) note2.clone();
//Customized to no sugar
oreder2.setSugarLevel(SugarLevel.NOSUGAR);
oreder2.printOrderDetails();
System.out.println("*********************************************************************************");
//Original Note for hot milk tea with normal sugar
TeaCoffeeOrder note3 = shop.similarOrders.get(HOT_MILKTEA_WITH_NORMALSUGAR);
note3.printOrderDetails();
System.out.println("---------------------------------------------------------------------------------");
//Order(Cloned) for hot milk tea with normal sugar
TeaCoffeeOrder oreder3 = (TeaCoffeeOrder) note3.clone();
oreder3.printOrderDetails();
System.out.println("*********************************************************************************");
}
}
Result
Tea Shop Name :SPSN Bhavan
*********************************************************************
This is Original Object with below details:
HotTEA Without Milk and with NORMALSUGAR
———————————————————————–
This is Prototyped/Cloned Object with order Number :6239
You have ordered HotTEA Without Milk and with LESSSUGAR
********************************************************************
This is Original Object with below details:
ColdCOFFEE Without Milk and with NORMALSUGAR
———————————————————————–
This is Prototyped/Cloned Object with order Number :5889
You have ordered ColdCOFFEE Without Milk and with NOSUGAR
********************************************************************
This is Original Object with below details:
ColdTEA With Milk and with NORMALSUGAR
———————————————————————–
This is Prototyped/Cloned Object with order Number :1015
You have ordered ColdTEA With Milk and with NORMALSUGAR
********************************************************************