You can see this and other great articles on design patterns here.
The prototype design pattern allows you to avoid expensive initialization routines when you construct objects that are very similar. The goal is to minimize the amount of work needed in creating new objects when the initialization routines are expensive. For example, if the initialization routine requires database queries, file lookups, or service calls and you already have other objects in the system that are very similar to the object you are constructing, then the prototype pattern may help you to avoid those expensive initializations.
The concept of the prototype pattern is similar to a Word document template (prototype), where you create the template only once, then all the objects that you create afterwards use the template as the starting point to avoid repeating the work again.
Let's look at the UML of the prototype pattern first, then we will look at an example to see how it works. Below is the UML of the Prototype Design Pattern:

- The
PrototypeManager class is just a manager class that is used to add and retrieve prototypes by an index number, it has the following variable and methods:
prototypeList variable is the collection that stores all the prototype
AddPrototype method allows you to add a prototype to the collection and assigning it an index number
GetPrototype method allows you to retrieve a prototype from the collection using an index number
- The
IPrototype interface specifies the methods that all prototype classes must implement. It has the Clone method that returns an IPrototype interface.
- The
ConcretePrototype class is the actual prototype class, it implements the IPrototype interface and has the following property and method:
copyProperty variable holds the information that is prepopulated. If the variable value is changed then the new instances created will have the new value.
Clone method will make a copy of itself and return it. If the copyProperty is a value type (such as int or string), then you can just use shallow copy. If the copyProperty is a reference type (such as an object that contains other objects), then you will need to make deep copy of the variable.
The key to the prototype pattern is that you will create your first object with the expensive initializations, then store the values as a prototype in the repository. When you need to create the same object again, you can just get the copy of the prototype from the repository with all the values prepopulated.
While there are many supported ways of making shallow or deep copy of objects in various programming languages, for the purpose of understanding the prototype pattern, we will not dig into such details, but simply demonstrate the core concept of the prototype pattern.
A comparison between the prototype pattern and the flyweight pattern shows some similarities in the UML, in that both use a manager to store and retrieve the objects in the collection. But there is a clear difference between the two. The prototype pattern is used to create new objects that are similar in nature (hence it's a creational pattern), while the flyweight pattern is used to allow the application to point to the same instance of the object to save memory (hence it's a structural pattern).
Let's see an example. In our example, we will often need to create Configuration and UserProfile objects in the application, and both objects store information that are resource intensive and take a while to populate. The UML for the example is shown below:
The Configuration class has the fileInformation variable that takes a while to create. The same goes for the UserProfile class which has the databaseInformation variable that is resource intensive to create.
Below are the implementation code and the output of the prototype pattern using our example. Notice that it takes a while to create the prototype class for the first time, but subsequent objects created afterwards take no time at all:
using System.Collections.Generic;
using System.Threading;
class Program
{
static void Main(string[] args)
{
Configuration c = new Configuration();
DateTime startTime = DateTime.Now;
c.GetFileInformation(); DateTime endTime = DateTime.Now;
Console.WriteLine("First Configuration object took " +
endTime.Subtract(startTime).TotalSeconds + " seconds");
UserProfile p = new UserProfile();
startTime = DateTime.Now;
p.GetDatabaseInformation(); endTime = DateTime.Now;
Console.WriteLine("First UserProfile object took " +
endTime.Subtract(startTime).TotalSeconds + " seconds");
PrototypeManager manager = new PrototypeManager();
manager.AddPrototype(c, 0);
manager.AddPrototype(p, 1);
startTime = DateTime.Now;
(manager.GetPrototype(0).Clone()
as Configuration).ShowInformation(); endTime = DateTime.Now;
Console.WriteLine("Second Configuration object took " +
endTime.Subtract(startTime).TotalSeconds + " seconds");
startTime = DateTime.Now;
(manager.GetPrototype(1).Clone()
as UserProfile).ShowInformation(); endTime = DateTime.Now;
Console.WriteLine("Second UserProfile object took " +
endTime.Subtract(startTime).TotalSeconds + " seconds");
}
}
public interface IPrototype
{
IPrototype Clone();
}
public class PrototypeManager
{
private Dictionary<int, IPrototype> list = new Dictionary<int,IPrototype>();
public void AddPrototype(IPrototype p, int index)
{
list.Add(index, p); }
public IPrototype GetPrototype(int index)
{
return list[index].Clone();
}
}
public class Configuration : IPrototype
{
private string fileInformation;
public void GetFileInformation()
{
Thread.Sleep(5000); fileInformation = "Long file information";
}
IPrototype IPrototype.Clone()
{
Configuration c = new Configuration(); c.fileInformation = this.fileInformation; return c;
}
public void ShowInformation()
{
Console.WriteLine("Showing " + fileInformation);
}
}
public class UserProfile : IPrototype
{
private string databaseInformation;
public void GetDatabaseInformation()
{
Thread.Sleep(5000); databaseInformation = "Long database information";
}
IPrototype IPrototype.Clone()
{
UserProfile p = new UserProfile(); p.databaseInformation = this.databaseInformation; return p;
}
public void ShowInformation()
{
Console.WriteLine("Showing " + databaseInformation);
}
}

Liked this article? You can see this and other great articles on design patterns here.