loading...
Cover image for Prototype Design Pattern in C#

Prototype Design Pattern in C#

sherviniv profile image Shervin Ivari ・5 min read

According to GoF, the Definition is:
“Prototype Design Pattern specifies the kind of objects to create using a prototypical instance, and create new objects by copying this prototype”.
If I want to say it In simple words what Prototype Design Pattern is,
create a duplicate object or clone of the existing object. The first thing may come to your mind is why just not creating a new one from scratch.
When it comes to Complicated objects we cant do this approach so whats way?
Here Prototype Design Pattern Shines.

Real-world example

Two phones
Imagine a factory creates a new phone myphone10. Later they decided to create a new phone called myphone10 PRO.
It is a good idea to build everything from scratch or just reiterate the existing design of myphone10 and reuse it? As you see by reuse existing objects we are saving resources and time.
the Prototype Design Pattern is the same approach in software engineering.

Just a quick reminder

primitive types:
These value types are stored in “stack” memory and these value types are fixed in size. Basically, they store by Value like boolean or int.
non-primitive types:
A variable holds a reference to the value, then that type of data types are reference types like object or class.

Prototype Pattern Implementation in C#

colorful factory
let's see a scenario in a real-world application.
There is a factory that returns different objects based on what input you pass to it.
You need to create a lot of instances of an object and call the factory and receive different objects. In this case, it's better to create one instance of your base object and clone others from it.

Note: To make a variation of one instance it is better to clone instance instead of creating a new one.

We'll have two classes.PhoneSketch it's just a sketch with some detail also it contains info about Operation System. I don't want to make you engaged with implementation details so I try to make my classes as simple as possible.

    public class PhoneSketch
    {
        public PhoneSketch(string modelName ,string hardware, OperationSystem operationSystem)
        {
            (this.ModelName, this.Hardware, this.OS) = (modelName, hardware, operationSystem);
        }

        public string ModelName { get; set; }

        public string Hardware { get; set; }

        public OperationSystem OS { get; set; }
    }

    public class OperationSystem
    {
        public OperationSystem(string name, int version)
        {
            (this.Name, this.Version) = (name, version);
        }
        public string Name { get; set; }
        public int Version { get; set; }
    }

now we create new phone plan.

PhoneSketch myphone10plan = new PhoneSketch("myphone10","Ram 4 & ...", new OperationSystem("Android", 10));

some customers may prefer Ram 6.so we need new plan with the same properties available in myphone10 and improve it.
Let's take a look at obvious stuff that will not work look like for example.

var myphone10PROplan = myphone10plan ;

This Code will fail cause you just copy reference(shallow copy).
shallow vs deep
in shallow copy, both objects will look at the same block in memory cause they have the same reference to one object, what we really need is a deep copy.

Implement ICloneable Interface

ICloneable needs a method to be implemented called Clone().The clone method creates a new object that is a copy of the current instance.

  public class PhoneSketch : ICloneable
    {
        public PhoneSketch(string modelName, string hardware, OperationSystem operationSystem)
        {
            (this.ModelName, this.Hardware, this.OS) = (modelName, hardware, operationSystem);
        }

        public string ModelName { get; set; }

        public string Hardware { get; set; }

        public OperationSystem OS { get; set; }

        public object Clone()
        {
            return this.MemberwiseClone();
            //Or
            return new PhoneSketch(this.ModelName, this.Hardware, this.OS);
        }
    }

Usage

PhoneSketch myphone10plan = new PhoneSketch("myphone10", "Ram 4 & ...", new OperationSystem("Android", 10));

var myphone10PROplan = (PhoneSketch)myphone10plan.Clone();
myphone10PROplan.ModelName = "myphone10 Pro";
myphone10PROplan.Hardware = "Ram 6";

for example hardware store data in the string(obviously it must be an object) but for making implementation easy to understand I set type as a string. for now myphone10plan and myphone10PROplan are two different objects, but what we really do its kind of shallow copy or clone. We just make a new object from the existing one but dependent objects still have the same reference.OperationSystem is one of them in my example. let's see whats will happen if we change one of the dependencies.

myphone10PROplan.OS.Version= 11;

Console.WriteLine(myphone10plan.OS.Version.ToString());//Display 11
Console.WriteLine(myphone10PROplan.OS.Version.ToString());//Display 11

As you can see when comes to dependencies Clone brokes.This is the main diffrence between Clone and DeepCopy.
Prototype Design Pattern required deep copy so ICloneable is not the interface that you should be using.

Note: In most solutions avoiding Clone() is a good plan.

A simple way from C++

In the C++ programming language, a copy constructor is a special constructor for creating a new object as a copy of an existing object.
copy constructor Provide simple API with a constructor and gets the same type as a parameter.
Add new constructor to PhoneSketch class

public PhoneSketch(PhoneSketch duplicatemodel)
{
  (this.ModelName, this.Hardware, this.OS) = (duplicatemodel.ModelName, duplicatemodel.Hardware, new OperationSystem(duplicatemodel.OS));
}

Add new constructor to OperationSystem class

public OperationSystem(OperationSystem os)
{
  (this.Name, this.Version) = (os.Name, os.Version);
}

Usage

var dupmodel = new PhoneSketch(myphone10plan);

you specify constructor for every class, it may make other developers confused while they are creating classes if they don't have any idea about what constructor with the same object parameter is!? It's also not very idiomatic and not be good to be used in .Net.

Deep copy Through Serialization

if you take a Serializer and you serialize your object the serializer should serialize the entire tree. You can use binary or XML serializer but I prefer using JSON. by Newtonsoft.Json You will have full access to your models and you can customize them.
Here is binary Serializer sample

    public static class PrototypeHelper
    {
         public static T DeepCopyBinary<T>(this T self)
        {
            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, self);
                ms.Position = 0;

                return (T)formatter.Deserialize(ms);
            }
        }
    }

one of the problems with this approach is that you have to add [Serializable] attribute to all of your classes.as you see XML or Binary Serializerhave some requirements.
in my opinion Json way it much easier and better, cause not always you have access to classes to add an attribute, You just need JSON serializer. In this sample, I'm using Newtonsoft.Json.

   public static T DeepCopyJson<T>(this T self)
        {
            var serializedobj = JsonConvert.SerializeObject(self);
            return JsonConvert.DeserializeObject<T>(serializedobj);
        }

conclusion

Now you have a deep view what Prototype design pattern is and different ways of implantation of it.its up to you if you want implement interface or create contractors or just use Serialization.
if you have to create a lot of instances of an object and their same or similar to the main prototypical instance its good to use this pattern.
Thanks for reading and Happy Coding!

Posted on by:

Discussion

pic
Editor guide
 

Nice one. You can use => to make the constructors and methods terser.

 

Thanks for your tip. Actually my main goal is just the principle.