Design Patterns

Design Patterns: The Prototype Pattern

Pattern Type: Creational

Description

The prototype design pattern seeks to provide a single unitary interface to a single class type, all while allowing the underlying class type to be different.

This has a number of uses. For example, the GOF book illustrates the pattern through the use of a "Graphical Object," which can be used to create "Staves," "Notes," and "Time Signatures" in a music score editing application.

Underneath the hood, the client application can refer to everything as a "Graphical Object" that has a known set of methods and properties such as "Draw()" and "Colour," but is capable of drawing very different objects using just those known base elements.

Another interesting example of its use could lie in an electronic logic simulator, where user circuits built up from lower level components could be loaded into the application, and used as sub circuits in a larger design.

Each circuit, irrespective of its underlying type, could be instantiated and represented as a "SubCircuit" but have drastically different inner workings under the covers.

Diagram

Proto
Figure 1: A client/prototype diagram

Client: This is the consumer requesting the prototype object

Prototype: This is an interface or an abstractly defined class representing the single class type

Concrete Prototype: These are the actual implementations returned by the prototype master

Implementation in C#

To implement the prototype design pattern, you need an interface or abstract class. This abstract class is the "Class Type" that consumers of the prototype object will create instances of. In the following example, these will be "Car Objects."

The prototype itself, however, usually is just the "structure". The actual implementations are provided by actual classes that either follow a contract-based interface, or are abstracted from the super object; in this example, "Race Car" and "Saloon Car."

To start with, the main prototype may look something like the following:

namespace PrototypePattern
{
   public abstract class Car
   {
      public int TopSpeed { get; set; }
      public int EngineSize { get; set; }
      public string Colour { get; set; }

      public abstract Car Clone();
   }
}

Here, we stamp out the base class type, and make sure that the basic information we might hold is represented, and that we have in place a 'Clone' method to clone our object.

Concrete prototypes may then in turn look something like the following:

namespace PrototypePattern
{
   public class SportsCar : Car
   {
      public override Car Clone()
      {
         return this.MemberwiseClone() as Car;
      }

   }
}

You only need to implement the Clone operation to make this a prototypical instance, but the clone can have any manner of other options attached to it after the fact.

There is an inherent danger to be aware of, however, and that's the subject of how deep the copy goes.

Memberwise Clone will create what is known as a shallow copy.

This means that your first level objects such as the "TopSpeed," "EngineSize," and "Colour" properties shown above will be copied faithfully into an entirely separate and new instance of the object when it's cloned.

Any sub objects, however, will have their "Reference" cloned, but not an actual copy.

What this means in practice is that if you have any nested objects, which you then take a clone of as part of the parent object, a change to the property on the new clone will also update the same instance on the parent.

To make the clone work in a "Deep" fashion, you not only need to make a copy using a Memberwise clone, but you then need to "new" up a new copy of the sub object, then manually copy the values across, like so

      public override Car Clone()
      {
         var clone = this.MemberwiseClone() as Car;

         clone.embeddedObject = new EmbeddedObject();
         clone.embeddedObject.property =
            this.embeddedObject.property;

         return clone;
      }

Doing this ensures that you detach the embedded class from the copy attached to the master prototype, and then make sure it has the same values as previous.

In many cases, it makes more sense, especially under .NET, to use interfaces to create a prototypical instance. The pattern is closely related and in many ways a competitor to the "Abstract Factory" pattern. Generally, however when using the Prototype pattern you would manage object creation via a "Prototype Manager" that would keep close tracking on which patterns are used and where.

If you have a Design Pattern you'd like to see implemented in C#. drop me a comment below. Until next month, practice makes perfect.

Shawty



About the Author

Peter Shaw

As an early adopter of IT back in the late 1970s to early 1980s, I started out with a humble little 1KB Sinclair ZX81 home computer. Within a very short space of time, this small 1KB machine became a 16KB Tandy TRS-80, followed by an Acorn Electron and, eventually, after going through many other different machines, a 4MB, ARM-powered Acorn A5000. After leaving school and getting involved with DOS-based PCs, I went on to train in many different disciplines in the computer networking and communications industries. After returning to university in the mid-1990s and gaining a Bachelor of Science in Computing for Industry, I now run my own consulting business in the northeast of England called Digital Solutions Computer Software, Ltd. I advise clients at both a hardware and software level in many different IT disciplines, covering a wide range of domain-specific knowledge—from mobile communications and networks right through to geographic information systems and banking and finance.

Related Articles

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date