Prototype Definition
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
Class Diagram
Participants
- Prototype
- declares an interface for cloning itself.
- ConcretePrototype.
- implements an operation for cloning itself.
- Client.
- creates a new object by asking a prototype to clone itself.
Example: Product Cache
When object instantiation is a lot more expensive than cloning, Prototype pattern may offer a useful optimization technique.
Example assumptions:
- An e-commerce application gathers product information trough complex queries against a legacy database.
- The legacy database is updated at predefined intervals which are known.
- The number of products allows caching with a reasonable memory consumption.
When a user asks for information for a certain product the application could gather that information in two ways:
- execute the complex query against legacy database, gather the information, and instantiate the object.
- instantiate the objects at predefined intervals and keep them in a cache, when an object is requested, it is retrieved from cache and cloned. When the legacy database is updated, discard the content of the cache and re-load with new objects.
The second approach is based on Prototype pattern and it is illustrated below:
Example: Class Diagram
Example: Java sample code
public abstract class Product implements Cloneable {
private String SKU;
private String description;
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
public String getDescription() {
return description;
}
public String getSKU() {
return SKU;
}
public void setDescription(String string) {
description = string;
}
public void setSKU(String string) {
SKU = string;
}
}
public class Book extends Product {
private int numberOfPages;
public int getNumberOfPages() {
return numberOfPages;
}
public void setNumberOfPages(int i) {
numberOfPages = i;
}
}
public class DVD extends Product {
private int duration;
public int getDuration() {
return duration;
}
public void setDuration(int i) {
duration = i;
}
}
import java.util.*;
public class ProductCache {
private static Hashtable productMap = new Hashtable();
public static Product getProduct(String productCode) {
Product cachedProduct = (Product) productMap.get(productCode);
return (Product) cachedProduct.clone();
}
public static void loadCache() {
// for each product run expensive query and instantiate product
// productMap.put(productKey, product);
// for exemplification, we add only two products
Book b1 = new Book();
b1.setDescription("Oliver Twist");
b1.setSKU("B1");
b1.setNumberOfPages(100);
productMap.put(b1.getSKU(), b1);
DVD d1 = new DVD();
d1.setDescription("Superman");
d1.setSKU("D1");
d1.setDuration(180);
productMap.put(d1.getSKU(), d1);
}
}
public class Application {
public static void main(String[] args) {
ProductCache.loadCache();
Book clonedBook = (Book) ProductCache.getProduct("B1");
System.out.println("SKU = " + clonedBook.getSKU());
System.out.println("SKU = " + clonedBook.getDescription());
System.out.println("SKU = " + clonedBook.getNumberOfPages());
DVD clonedDVD = (DVD) ProductCache.getProduct("D1");
System.out.println("SKU = " + clonedDVD.getSKU());
System.out.println("SKU = " + clonedDVD.getDescription());
System.out.println("SKU = " + clonedDVD.getDuration());
}
}
Benefits
- Adding and removing products at runtime.
- Specifying new objects by varying values.
- Specifying new objects by varying structure.
- Reduced subclassing.
- Configuring an application with classes dinamincally.
Usage
- When the classes to instantiate are specified at run time.
- When you want to avoid building a class hierarchy of factories that parallels the class hierarchy of products.
- When instances of a class can have one of only a few combinations of state.
-----------------------------------------------------
Silence, the way to avoid many problems;
Smile, the way to solve many problems;