Prototype pattern is used to create an object from exiting object via cloning. Prototype pattern falls under creational pattern of GOF (Gang of Four) pattern.
When to use –
When you want to create an object by copying it from other object or prototype. So
prototype act as master or blueprint and other objects created from master object are copies of that object. In short, Prototype pattern is used to clone objects.
In real world example, a photocopy machine creates multiple copies from
original document and you can independently use or send photocopies wherever
you want to use original document.
Major components of prototype pattern are –
- Prototype – It’s an interface for cloning.
- Concrete Prototype – Implements prototype interface and clone itself.
- Client – Creates new object and ask to create clone of created object.
Prototype pattern is easy to implement. You can create your
own interface which contains Clone method and use it as prototype. In below
example I used ICloneable interface as Prototype.
Code –
public class Address
{
public string Line1 {
get; set; }
public string City { get; set; }
public string Country
{ get; set; }
public override string
ToString()
{
return string.Format("Line1
: {0}, City : {1}, Country : {2}", Line1, City, Country);
}
}
//ConcretePrototype
public class Person : ICloneable
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address
{ get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
public override string
ToString()
{
return string.Format("Name
: {0}, Age : {1}, Address : {2}", Name, Age, Address.ToString());
}
}
//Client
class Program
{
static void Main(string[] args)
{
//New Person object
Person p1 = new Person() {
Name = "Mitesh", Age = 30, Address = new Address() {
Line1 = "Addr 1", City = "Pune",
Country = "India" } };
Console.WriteLine("---------P1-----------");
Console.WriteLine(p1.ToString());
//Clone person object from existing
P1 object
Person p2 = (Person)p1.Clone();
Console.WriteLine("---------P2-----------");
Console.WriteLine(p2.ToString());
//Modify P2 object
p2.Name = "John";
p2.Age = 40;
p2.Address.Line1 = "A1";
p2.Address.City = "Atlanta";
p2.Address.Country = "USA";
Console.WriteLine("---------P1-----------");
Console.WriteLine(p1.ToString());
Console.WriteLine("---------P2-----------");
Console.WriteLine(p2.ToString());
Console.ReadLine();
}
}
Output –
In above example, I used MemberwiseClone () method which is
available to all objects. This method creates shallow copy of an object. This
method copies the values of all the fields and doesn’t copy references in the
object points to. When object is simple and doesn’t contain any references of
other objects then this method works very well. In above example I changed
address of P2 object then it has also changed address of P1 object as well and this
is not expected when you clone an object. To solve this problem, we need to use deep copy functionality to copy an object. See below example with little change in Clone
method to implement deep copy.
Code –
public class Address
{
public string Line1 {
get; set; }
public string City { get; set; }
public string Country
{ get; set; }
public override string
ToString()
{
return string.Format("Line1
: {0}, City : {1}, Country : {2}", Line1, City, Country);
}
}
//ConcretePrototype
public class Person : ICloneable
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address
{ get; set; }
public object Clone()
{
//Shallow copy
Person obj
= (Person)this.MemberwiseClone();
//Deep copy
obj.Address = new Address() {
Line1 = this.Address.Line1, City = this.Address.City,
Country = this.Address.Country };
return obj;
}
public override string
ToString()
{
return string.Format("Name
: {0}, Age : {1}, Address : {2}", Name, Age, Address.ToString());
}
}
//Client
class Program
{
static void Main(string[] args)
{
//New Person object
Person p1 = new Person() {
Name = "Mitesh", Age = 30, Address = new Address() {
Line1 = "Addr 1", City = "Pune",
Country = "India" } };
Console.WriteLine("---------P1-----------");
Console.WriteLine(p1.ToString());
//Clone person object from existing
P1 object
Person p2 = (Person)p1.Clone();
Console.WriteLine("---------P2-----------");
Console.WriteLine(p2.ToString());
//Modify P2 object
p2.Name = "John";
p2.Age = 40;
p2.Address.Line1 = "A1";
p2.Address.City = "Atlanta";
p2.Address.Country = "USA";
Console.WriteLine("---------P1-----------");
Console.WriteLine(p1.ToString());
Console.WriteLine("---------P2-----------");
Console.WriteLine(p2.ToString());
Console.ReadLine();
}
}
Output –
As you can see in above example, I made changes in Clone
method and implemented deep copy functionality to copy reference object along
with other values of object. Now you can see there is no change in P1 object’s
address after changing P2 object’s address. It means implementing deep copy
in prototype pattern we get brand new P2 object from prototype which has no
relation with P1 object.
Difference between shallow copy and deep copy –
Shallow Copy
|
Deep Copy
|
Copies value types from source object to target object. It also
copies object’s reference type as reference but not the referenced object
itself.
|
Deep copy makes a complete copy of value types and reference types
with actually coping it’s reference object.
|
Shallow copy objects are not 100% disconnected to its original
object.
|
Deep copy objects are 100% disconnected to its original object.
|
MemeberwiseClone() method used to create Shallow copy of an object.
|
Need to override Clone method to modify object returned from
MemeberwiseClone() to copy actual reference types.
|
Shallow copy is fast and less expensive
|
Deep copy is slow and expensive compare to shallow copy.
|
Shallow copy preferred when object has primitive types.
|
Deep copy is preferred when object has references to other objects.
|
Hope this article helps you to understand Prototype Pattern.
Please leave your feedback in comments below.
References –
See Also –
Creational Patterns
|
Structural Patterns
|
Behavioral Patterns
|
|
||
|
|
|
|
|
|
|
|
|
|
|
No comments:
Post a Comment