Prototype Pattern - Creational: Intent
Prototype Pattern - Creational: Intent
Intent:
To specify the kinds of objects to create using a prototypical instance, and create
new objects by copying this prototype.
Motivation:
Example 1:
In building stages for a game that uses a maze and different visual objects that the
character encounters it is needed a quick method of generating the haze map using
the same objects: wall, door, passage, room…
The Prototype pattern is useful in this case because instead of hard coding (using
new operation) the room, door, passage and wall objects that get instantiated,
CreateMaze method will be parameterized by various prototypical room, door, wall
and passage objects, so the composition of the map can be easily changed by
replacing the prototypical objects with different ones.
The Client is the CreateMaze method and the ConcretePrototype classes will be the
ones creating copies for different objects.
Example 2:
Suppose we are doing a sales analysis on a set of data from a database. Normally,
we would copy the information from the database, encapsulate it into an object and
do the analysis.
But if another analysis is needed on the same set of data, reading the database
again and creating a new object is not the best idea. If we are using the Prototype
pattern then the object used in the first analysis will be cloned and used for the other
analysis.
The Client methods process the object that encapsulates information from the
database. The ConcretePrototype class will be class that creates the object after
extracting data from the database, will copy it into objects used for analysis.
Applicability:
Use prototype pattern when a system should be independent of how its products are
created, composed and represented and:
Structure:
Participants:
Collaborations:
A client asks a prototype to clone itself.
Consequences:
Main drawback of prototype pattern is that each sub class of Prototype must
implement the clone operation, which may be difficult
Implementation:
?
1 abstract class AbstractProduct implements Cloneable
2 {
3 public static AbstractProduct thePrototype;
4 public static AbstractProduct makeProduct()
5 {
6 try
{
7 return (AbstractProduct) thePrototype.clone();
8 }
9 catch(CloneNotSupportedException e)
10 {
11 return null;
}
12 }
13 }
14
15 class ConcreteProductA extends AbstractProduct { }
16
17 class ConcreteProductB extends AbstractProduct { }
18
19 public class PrototypeDemo
{
20 public static void main(String[] args)
21 {
22 AbstractProduct.thePrototype = new ConcreteProductA();
23 AbstractProduct product = AbstractProduct.makeProduct();
24 System.out.println(product);
}
25 }
26
27
28
Implementation Issues:
Using a prototype manager:
When the application uses a lot of prototypes that can be created and destroyed
dynamically, a registry of available prototypes should be kept. This registry is called
the prototype manager and it should implement operations for managing registered
prototypes like registering a prototype under a certain key, searching for a prototype
with a given key, removing one from the register, etc.
The clients will use the interface of the prototype manager to handle prototypes at
run-time and will ask for permission before using the Clone() method.
Usually, a shallow clone is enough and very simple, but cloning complex prototypes
should use deep clones so the clone and the original are independent, a deep clone
needing its components to be the clones of the complex object’s components.
Initializing clones:
There are cases when the internal states of a clone should be initialized after it is
created. This happens because these values cannot be passed to the Clone()
method, that uses an interface which would be destroyed if such parameters were
used.
In this case the initialization should be done by using setting and resetting operations
of the prototype class or by using an initializing method that takes as parameters the
values at which the clone’s internal states should be set.
Sample Code:
We’re going to create an abstract class Shape and concrete classes extending
the Shape class. A class ShapeCache is defined as a next step which stores shape
objects in a Hashtable and returns their clone when requested
1
2 public class Rectangle extends Shape
3 {
public Rectangle()
4 {
5 type = "Rectangle";
6 }
7 @Override
8 public void draw()
{
9 System.out.println("Inside Rectangle::draw() method.");
10 }
11 }
12
Square.java
1
2 public class Square extends Shape
3 {
public Square()
4 {
5 type = "Square";
6 }
7 @Override
8 public void draw()
{
9 System.out.println("Inside Square::draw() method.");
10 }
11 }
12
Circle.java
1
2 public class Circle extends Shape
3 {
public Circle()
4 {
5 type = "Circle";
6 }
7 @Override
8 public void draw()
{
9 System.out.println("Inside Circle::draw() method.");
10 }
11 }
12
Create a class to get concreate classes from database and store them in
a Hashtable.
ShapeCache.java
?
1
2
3 import java.util.Hashtable;
public class ShapeCache
4 {
5 private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
6 public static Shape getShape(String shapeId)
7 {
8 Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
9 }
10 public static void loadCache()
11 {
12 Circle circle = new Circle();
13 circle.setId("1");
shapeMap.put(circle.getId(),circle);
14 Square square = new Square();
15 square.setId("2");
16 shapeMap.put(square.getId(),square);
17 Rectangle rectangle = new Rectangle();
18 rectangle.setId("3");
shapeMap.put(rectangle.getId(),rectangle);
19 }
20 }
21
22
PrototypePatternDemo.java
?
1
2 public class PrototypePatternDemo
3 {
public static void main(String[] args)
4
{
5 ShapeCache.loadCache();
6 Shape clonedShape = (Shape) ShapeCache.getShape("1");
7 System.out.println("Shape : " + clonedShape.getType());
8 Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
System.out.println("Shape : " + clonedShape2.getType());
9
Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
10 System.out.println("Shape : " + clonedShape3.getType());
11 }
12 }
13
Known Uses:
The first widely known application of the pattern in an object-oriented language was
in ThingLab, where users could form a composite object and then promote it to a
prototype by installing it in a library of reusable objects. Prototype is used in Etgdb.
Etgdb is a debugger front-end based on ET++ that provides a point-and-click
interface to different line-oriented debuggers. The “interaction technique library” in
Mode Composer stores prototypes of objects that support various interaction
techniques.
Related Patterns:
Prototype and Abstract Factory patterns can be used together. Designs that make
heavy use of the Composite and Decorator patterns often can benefit from Prototype
as well.
The Prototype pattern specifies the kind of objects to create using a prototypical
instance. Prototypes of new products are often built prior to full production, but in this
example, the prototype is passive, and does not participate in copying itself.
The mitotic division of a cell, resulting in two identical cells, is an example of a
prototype that plays an active role in copying itself and thus, demonstrates
the Prototype pattern. When a cell splits, two cells of identical genotype result. In
other words, the cell clones itself.