Object Oriented Programming Patterns for Geeks
The Prototype Pattern
In .NET this pattern is catered for in some respects via the 'ICloneable' interface. In C++ the use of copy constructors can achieve a similar result. However, with .NET there is a caveat in respect to the protected object method 'MemberwiseClose()'. The example below demonstrates the .NET version of this pattern and highlights the issue.
namespace ooppatterns
{
using System;
internal class Program
{
private static void Main( string[] args )
{
// Using .NET's standard 'Shallow copy' Memberwise close
Prototype PT = new Prototype();
Prototype PT2 = PT.Clone() as Prototype;
Console.WriteLine( PT.SomeData );
Console.WriteLine( PT.SomeObj.Test );
// Notice this is assigning to 'PT' and NOT 'PT2'
PT.SomeObj.Test = "food!";
Console.WriteLine( PT2.SomeData );
Console.WriteLine( PT2.SomeObj.Test );
// Using an explicit implementation...
PrototypeDeep PTD = new PrototypeDeep();
PrototypeDeep PTD2 = PTD.Clone() as PrototypeDeep;
Console.WriteLine( PTD.SomeData );
Console.WriteLine( PTD.SomeObj.Test );
PTD.SomeObj.Test = "food!";
Console.WriteLine( PTD2.SomeData );
Console.WriteLine( PTD2.SomeObj.Test );
Console.ReadLine();
}
}
class Prototype : ICloneable
{
private int _someData = 100;
private SomeObject _someObj = new SomeObject();
public int SomeData
{
get { return this._someData; }
set { this._someData = value; }
}
public SomeObject SomeObj
{
get { return this._someObj; }
set { this._someObj = value; }
}
public object Clone()
{
// This performs a shallow copy, which means
// values are copied 'as is' - this includes
// references, so cloned objects will share
// reference objects - not clever!
return base.MemberwiseClone();
}
}
class PrototypeDeep : ICloneable
{
private int _someData = 100;
private SomeObject _someObj = new SomeObject();
public int SomeData
{
get { return this._someData; }
set { this._someData = value; }
}
public SomeObject SomeObj
{
get { return this._someObj; }
set { this._someObj = value; }
}
public object Clone()
{
// This ignores the .NET shallow-copy and
// is more explicit.
PrototypeDeep PTD = new PrototypeDeep();
PTD._someData = this._someData;
PTD._someObj = new SomeObject(); // Notice new instantiation.
PTD._someObj.Test = this._someObj.Test; // assign data to new object
return PTD;
}
}
class SomeObject
{
private string _test = "hello";
public string Test
{
get { return this._test; }
set { this._test = value; }
}
}
}