Understanding and Implementing Prototype Pattern in C# – Implementing ICloneable Interface and understanding Shallow and Deep Copy

This article talks about the prototype pattern, when should it be used. We will then see how the prototype pattern can be implemented in C#. Also, this article will discuss about the shallow copy and deep copy in C# and how can we implement ICloneable interface to implement prototype pattern in a .Net optimized way.

Background

There are many situations in our applications where we want to take an object’s copy from the context and then proceed with this copy with some independent set of operations. Prototype pattern is specifically useful in such scenarios where we can simply copy an object from the current application context and then proceed with it independent of the original object.

GoF defines prototype pattern as “Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.” so to visualize this pattern let us look at the class diagram of this pattern.

GofPrototype

In the above diagram the major players involved are:

  • Prototype: This is an interface or abstract class that defined the method to clone itself.
  • ConcretePrototype: This is the concrete class that will clone itself.
  • Client: The application object that need the cloned copy of the object.

Let us now try to see how we can implement this pattern in C#.

Using the code

To illustrate this pattern, we need a scenario where we need to clone an existing object. For the sake of simplicity I have taken a rudimentary and hypothetical example of a famous auto theft game.

Lets say we have a protagonist in the game. The protagonist has some statistics to define his playing variables. Now whenever we need to save the game the clone of this object will be taken and serialized on the disk(only for this example, this is seldom the case in real games).

So to get a copy of this Protagonist object the Protagonist object is defined in such a way that cloning it should be possible. So the following abstract class defines the Prototypeobject that we saw in above class diagram.

This interface defines all the vital information required for the player and a clone method so that the object can be cloned. Now lets say we need to spawn a concrete player name CJ in the game. This player should be Cloneable so that whenever we need to save the game we can simply clone the object and intitiate the serialization process asynchronously.

Now this class is the ConcretePrototypethat provides the facility to clone itself. In this example the ConcretePrototype does not contain any specialized members of its own but in some cases this class could contain some member variable or functions of its own.

Now let us see how the client code will be written to clone this object.

normal

Understanding Shallow copy and Deep copy

The above code perfectly illustrates the prototype pattern in action. There is one problem though. We are using the method MemberwiseCopyin our implementation. The problem with the memberwise copy is that it creates a shallow copy of the object i.e. if the object contains any reference types then only the address of that reference type will be copied from source to target and both the versions will keep pointing to the same object.

To illustrate this point lets have a class called AdditionalDetails containing more information about the Protagonist.

Now the extended version of our abstract class will contain a member variable for the AdditionalDetailsobject.

And the Concrete class will still perform a clone operation using Memberwisecopyfunction.

Now the problem with this is that after copy both the versions will be pointing to the same object of the AdditionalDetials.

ShallowCopy

To visualize this problem:

shallowIllus

To avoid this what we need to do is to create a copy of the internal reference type on the heap and then assign that new object with the copy being returned.

Now when we run the above client code the internal object’s separate copy will be returned.

deepCopy

Note: Care must be taken to perform a deep copy because the reference type could still contain reference types internally. The ideal way to do a deep copy is to use reflections and keep copying recursively until the primitive types are reached. For details refer this.

So having a shallow copy and deep copy in our object is totally the decision based on the functionality required but we have seen both the ways of doing the copy.

Implement ICloneable interface for Prototype Pattern

The ICloneableinterface in C# serves the purpose of defining the clonemethod in the objects. We can use the ICloneableinterface as Prototype(from the above class diagram). So let us see the implementation of the ConcretePrototype by implementing the ICloneableinterface.

The client code will now be:

IcloneableCopy

Point of interest

In this article, we saw what is prototype pattern. How can we implement Prototype pattern in C#. We looked at the Shallow copy and Deep copy concepts in C# and see how can we implement the ICloneable interface in C#. I hope this has been a little informative.

Download sample code for this article: PrototypeDemo