Welcome to my Design Pattern For Beginners article series. In the previous two articles of the series I explained the Singleton Design Pattern and Factory Design Pattern, you can read about them here:
In today's article we will learn one more very common design pattern called "Prototype Design Pattern".
As the name suggests, prototype means making a copy of something that exists. In this context let me give one nice example. A few days ago one of my friends went to a Tattoo shop to get a Tattoo on his body. (Yes my friend is cool and rocking in nature.) After returning from the shop (with a tattoo in hand) he told me, Sourav, they have some preprepared styles that are very less costly but if we want our own design, then they said "it will take time and the cost will be higher". I said Ok. Now consider this for the situation in software development. If the client demands an object that we already have then we can deliver it very quickly and at less cost. In software development there are many scenarios where the same copy of an existing object is frequently needed.
And this is the basic necessity of the Prototype Design Pattern. So, let's clarify the basic requirement "when we need to create the same object again and again then we will implement a Prototype Design Pattern". Here is the simple logical diagram of the Prototype Design Pattern:
Now, one big misconception occurs when we (basically junior programmers, including me) creates the same object in C# or tries to copy one object into another. Let's learn the problem at first. Then we will see how to solve it.
Have a look at the following code; here we will try to create a copy of an existing object.
using System;
using System.Collections;
using System.Globalization;
namespace Test1
{
class Test
{
public string Name;
}
class Program
{
static void Main(string[] args)
{
Test obj1 = new Test();
obj1.Name = "sourav";
Test obj2 = obj1; // Trying to make copy in obj2
obj2.Name = "c-sharpcorner.com";
Console.WriteLine(obj1.Name);
Console.ReadLine();
}
}
}
And here is the output:
In this code we are trying to make a copy of one object into another by the following statement:
Test obj2 = obj1;
And we are thinking that one copy of obj1 is getting stored in obj2. But due to the primary concept of the object being a reference type, in other words if we initialize one object to another object then they both point to the same memory location where the actual value is present.
Now the next line is the most interesting. We are initializing a property (data member) of obj2. Here we will see the concept behind the screen. When we initialize obj1 to obj2, then both are:
They both point to the same memory location. (Generally in heap memory and obj1 and obj2 are created on the top of the stack.) In the next line, when we are setting the property of obj2, it is automatically reflected to obj1. And that is the reason why, when we are trying to print the property of obj1 (initialized to "Sourav") we are getting the value of obj2 (c-sharpcorner.com).
Now this is the problem and we are sure that in this example not at all objects are created from the same copy. Then what is the solution?
Let's use MemberwiseClone() function
Yes, this is the solution. In the following example we will see how to implement the MemberwiseClone() function to copy the same object to another object.
using System;
using System.Collections;
using System.Globalization;
namespace Test1
{
class Test
{
public string Name;
public Test CloneMe(Test t)
{
return (Test)this.MemberwiseClone();
}
}
class Program
{
static void Main(string[] args)
{
Test obj1 = new Test();
obj1.Name = "sourav";
Test obj2 = obj1.CloneMe(obj1); // Trying to make copy in obj2
obj2.Name = "c-sharpcorner.com";
Console.WriteLine(obj1.Name);
Console.ReadLine();
}
}
}
Here is the output.
Oh! At last we have found the right solution to make a copy of the object. And this an example of the Prototype Design Pattern.
Hmm...You are thinking, okay "I understood Prototype pattern but the example is meaningless". Dear reader, I did not forget my promise that I made in my first article of the Design Pattern Series. (If you want to hear it please visit here.)
Let's talk about a scenario where the Prototype Design Pattern is relevant.
Consider that you want to create one copy of an object multiple times. For your birthday you want to send an invitation letter to your friends, now the content and sender name will remain the same whereas the recipient name will only change. In this situation we can use a prototype of the invitation card for multiple friends.
Take another example, where one object will be created after heavy database operations (as we know, database operations are very costly) and we want that object 100 times. What if we make a clone of the same object by the Prototype Desing Pattern rather than hitting the database 100 times? Good solution right?
Ok, I am talking too much. Let's implement our first scenario in C# code. Here is the sample code.
using System;
using System.Collections;
using System.Globalization;
namespace Test1
{
class InvitationCard
{
public String To;
public String Title;
public String Content;
public String SendBy;
public DateTime Date;
public String p_To
{
get { return To; }
set { To = value; }
}
public String p_Title
{
get { return Title; }
set { Title = value; }
}
public String p_content
{
get { return Content; }
set { Content = value; }
}
public String p_SendBy
{
get { return SendBy; }
set { SendBy = value; }
}
public DateTime p_Date
{
get { return Date; }
set { Date = value; }
}
public InvitationCard CloneMe(InvitationCard obj)
{
return (InvitationCard)this.MemberwiseClone();
}
}
class Program
{
static void Main(string[] args)
{
InvitationCard obj1 = new InvitationCard();
obj1.p_To = "Ram";
obj1.p_Title = "My birthday invitation";
obj1.p_content = "Hey guys !! I am throwing a cheers party in my home";
obj1.SendBy = "Sourav";
obj1.p_Date = Convert.ToDateTime(DateTime.Now.ToShortDateString());
//Here our first object has created
InvitationCard[] objList = new InvitationCard[5];
String[] nameList = { "Ram", "Shyam", "Hari", "Tapan", "Sukant" };
int i = 0;
foreach (String name in nameList)
{
//objList[i] = new InvitationCard();
objList[i] = obj1.CloneMe(obj1);
objList[i].p_To = nameList[i];
i++;
}
// Print all Invitation Card here
foreach (InvitationCard obj in objList)
{
Console.WriteLine("To :- " + obj.p_To);
Console.WriteLine("Title :- " + obj.p_Title);
Console.WriteLine("Content :- " + obj.p_content);
Console.WriteLine("Send By :- " + obj.p_SendBy);
Console.WriteLine("Date :- " + obj.Date);
Console.WriteLine("\n");
}
Console.ReadLine();
}
}
}
And here is the output of what we expected:
(Guys, believe me or not. I am writing this article and its 23:50, in other words it is 11.50PM at night and in 10 minutes it's my birthday on 8-8-2013).
And here for the sake of simplicity of the example we have invited only five friends. Now think about my crazy friend (the Tattoo fellow). He has a few hundred friends and he too wants to invite them all. If we use the Factory Design Pattern and give him one application then we wish his problem is solved.