design pattern

Creational Design Patterns: Prototype

Our next stop during our travels through the Guide to Software Design Patterns series has us exploring another Creational technique known as the prototype pattern. In the simplest terms, the prototype pattern allows for a new instance of an object to be created by duplicating or cloning an existing object, as opposed to creating a new object instance outright.

In this article we’ll explore the prototype pattern through both some real world instances and a functional C# code example, so let’s get started!

In the Real World

A common example of prototyping, or cloning, which most computer users are familiar with, is when we copy a file on our hard drive. By selecting a text document on your desktop, then hitting Ctrl/Cmd+C then Ctrl/Cmd+V, you’re asking your computer to create a clone of that text document. In essence, your system is analyzing the existing document and duplicating of all the relevant bits and bytes that make up that entity. A rather complex process behind the scenes, but a very straightforward example of everyday cloning that most of us experience.

To bring a bit more life into it, another real world example of cloning occurred back in 1996, when Dolly the Sheep was born, making her the first successful cloning of a mammal through a process known as nuclear transfer. This success has led to numerous other mammalian clones including deer, horses, bulls, and even four identical clones of the original Dolly as of July 2016. Wild stuff!

How It Works In Code

To illustrate how prototyping works within actual C# code we’ll stick to our tried-and-true topic of books. As usual, we’ll start with the full working code example that you can copy and modify yourself, after which we’ll walk through it step-by-step to see what’s going on and how prototyping is typically implemented:

As usual we begin with a baseline object, which is our Book class in this case. Book uses the IBook interface, which just specifies a few simple properties our Book class must declare: Title, Author, and Pages. Pages is of particular note because we have a separate Pages class with its own PageCount property that tracks the actual number of pages. The reason for this abstraction of Pages as a separate class will become apparent shortly:

It’s also worth noting that, in addition to the IBook interface, our Book class also inherits the ICloneable interface.ICloneable is an interface provided by the .NET API that contains only one member, the Clone method. By using this interface, we’re forcing our Book class to declare a Clone method, which we’ve specified:

This is a basic way of cloning an object in C#, through the use of the MemberwiseClone method. Using MemberwiseClone method to clone an object creates what is called a shallow clone. A shallow clone of an object copies all the nonstatic fields of the source object. This works fine for simple fields like Strings or Integers, but what happens when a field is just a reference type to another object (as in the case of the Book#Pages field, which is a reference to the Pages class object)? The shallow clone copies the reference to that object, but the actual referenced object is not copied. This means that our shallow clone, created via the MemberwiseClone method within our Clone instance method, will not retain the proper Pages object instance that has been created.

This is why we also have added a DeepClone method to the Book class:

While we begin with a MemberwiseClone call just as before, we then explicitly assign the property values of our clone object to be the same as the corresponding Book object properties. This is particularly important for the clone.Pages property assignment, where we explicitly generate a new instance of Pages with the appropriate PageCount property value passed into it.

To see how this all comes together, we can call our Book class and create some clones. We start by creating a new instance of Book called book, then immediately create a shallow clone, after which we output the values of both our Base Book and Shallow Clone:

The output shows that all properties are identical across both books, as expected:

Now, let’s see what happens when we modify the Title and Pages.PageCount properties of our Base Bookinstance:

The produced output:

What’s particularly important to note here is which properties changed and which didn’t. Because we created a shallow clone, after we modified the Title property of book our shallowClone instance retained the original Title property it was given. However, changing the Pages.PageCount property of the base book instance also causes that same change to propagate to our shallowClone. As discussed above, this is because a shallow clone of an object retains all references to outside objects that it might have. In this case, the Pages property of our instances are simply a reference to the Pages class instance, which both the base book and shallowBook continue to share.

This behavior may often be desired when using the prototype pattern, but in cases where separation is required we can use the DeepClone method of our Book class, like so:

Again, we start with the same base book instance, and from that we create a deepClone instance. The output shows, as expected, that both contain the same properties at this point:

However, now let’s see what happens when we make the same modifications to the base book instance by changing Title and Pages.PageCount:

Unlike with the shallow clone technique, our deepClone instance does not copy the reference to the same Pagesclass instance of our base book instance. Therefore, deepClone has its own unique instance, retaining the original Pages.PageCount value of 694: