The Prototype pattern gives us a way to deal with creating new instances of objects from existing object instances. We basically produce a copy or clone of a class that we already have created and configured. This allows us to capture the present state of the original object in its clone so we can modify the cloned object without introducing those changes to the original. We might do this if we needed to duplicate a class for some reason but creating a new class was not appropriate.
Perhaps the class we wanted to clone had a particular internal state we wanted to duplicate. Creating a new class from scratch would not reproduce the appropriate internal variable values in the new class we desired without violating rules of encapsulation of the class. This might occur because we might not be able to directly access private variables inside the class. Simply constructing a new class would not get us the class in its current state. Making a clone of the existing class would allow the clone to be modified and used without changing the original and would allow us to capture the originating class's state in the new class. This can be accomplished because the prototype method is internal to the originating class, and has access to its class's internal variables. This gives the method direct access to both the originating and the new class's internal state.
Another reason to use a prototype would be because we cannot create a new class in the current scope of the code or because allowing a constructor on the class in the current scope violates the rules of encapsulation of our application. A situation like this could occur if the class's constructor was marked internal to a domain that is not the current domain. We could not call the constructor because of its encapsulation properties. This sometimes happens in cases where a facade is used. Since you cannot call the constructor outside of the facade's domain, the only way to construct a new instance of a class would be to provide a prototype method on the class.
The Prototype pattern has one main component: the Prototype. The prototype is really an ordinary class that has a method implemented to create a copy (or clone) of itself.
This is an interesting and useful pattern. Let's take a look at some examples of how it can be used.

Problem: A class that cannot be constructed outside its assembly or package needs a copy made that keeps its current state intact
For our example, we start with a class that can only be constructed internally to an assembly or package. We need to create a new instance of the class in a scope that is outside of the assembly or package of the class. Since the constructor is marked internal to its domain, assembly, or package, we cannot call it in the current scope.
The Stone class needs to be added to another class outside its package or assembly without sharing the current reference. The only way to do that is to call the factory method again and get a new instance. This might be inappropriate since the Stone class may have changed attributes that we wish to maintain in the new class. We have tried to fix this problem by creating a new class and filling its attributes with the values of the original:
Stone stone = StoneFactory.GetGranite();
stone.Color = System.Drawing.Color.DimGray;
stone.Hardness = 5;
stone.Shape = System.Drawing.Drawing2D.WarpMode.Bilinear;
Calling the factory to get a new class will give us a new instance, but we have to be careful to write the code so we can get an exact replica of the original:
Stone nonClonedStone = StoneFactory.GetGranite();
nonClonedStone.Color = stone.Color;
nonClonedStone.Hardness = stone.Hardness;
nonClonedStone.Shape = stone.Shape;
This will only work as long as we can set the internal variables of the class through methods providing external access to these variables. If we had attributes that we could not set inside the new class, this method would not work. Our problem is that we do have such variables; we just cannot modify the internal state of the class easily from outside the class. We need a way to get a new instance of the class with its complete state maintained in the new class.
Solution: Create a prototype method on the class to return a cloned instance with its state copied to the needed depth
Our solution to this dilemma is to build a method on the class that will produce a prototype of the original. In other words, we clone or copy the class with a method that has internal access to the class without violating the class's encapsulation rules.

Figure 2-12: UML for Prototype pattern example
We start by looking at the abstract Stone class. We provide an abstract method on the class named Clone(). This method will be implemented on the concrete implementations of the class to provide a way to return the particular instance of the class with its current state at the time of the call to the method.
abstract class Stone
{
public abstract Stone Clone();
}
Now let's look at the implementation class Granite and its Clone() method. We use the .NET MemberwiseClone() method to render a shallow copy of the attributes of the class in its current state:
class Granite : Stone
{
public override Stone Clone()
{
return (Granite)this.MemberwiseClone();
}
}
In the case of having data that lived deeper in the object, we might have to capture the internal state directly. This could occur, for instance, in an object containing collections of object instances, and the collections would not necessarily get cloned because the objects in them were reference types instead of value types. In this case, you might have to add each object manually. This is referred to as a deep copy. A deep copy occurs when you have copied new reference types from existing ones, in addition to using MemberwiseClone() to copy the value types, making a completely disconnected new class instance. This results in an object whose internal reference types are not shared but are new instances of the original reference types. This ensures changes to the cloned object's reference types do not affect the object from which it was cloned. In the following example, we are copying all the value types from the current object to a new object, then looping through the current object's internal collection and calling a clone object on the value type in the collection:
public override Stone Clone()
{
Stone ret = (Granite)this.MemberwiseClone();
foreach(object obj in _collection)
ret.Add(obj.Clone()); //Reference Type is also cloned
return ret;
}
Now when we call the method it produces an exact copy with the same internal state as the original class:
Stone clonedStone = stone.Clone();
Our test of the new class confirms this:
Cloned
Color:Color [DimGray]
Hardness:5
Shape:Bilinear
Comparison to Similar Patterns
Depending on the scope and purpose of the creational methods, either a Factory or a Singleton pattern might be a better solution than the Prototype pattern. If you need a global instance of a class that cannot be instanced more than once, then a Singleton might be more appropriate. A Factory might also be another option for a more global management site for the object's state. The Factory could retain created objects and their states, and render them as needed.
What We Have Learned
The Prototype pattern gives us another way to deal with creating a class when copying the original object's state is important. It is also useful when the object cannot be created in its current context without violating the object's encapsulation rules. The pattern basically provides a clone of the original object, maintaining all of the original object's current state.
Related Patterns
Factory pattern
Singleton pattern
Template pattern
No comments:
Post a Comment