Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Prototype Design Pattern

4.75/5 (14 votes)
23 Sep 2009CPOL4 min read 93.7K   667  
This article shows a case study about how we use the Prototype pattern to Elizabeth's fun activity

Background

From my last article, I introduced the builder pattern by using an example of Elizabeth's fun activity.

When Elizabeth wants to make animals, she needs to make a head, body, leg, arm and tail for each animal. She uses the mold tool set to make all the body parts of the animal first, and then puts them together to make an animal.

In her fun activity, Elizabeth uses the builder pattern to build the animals. For example, when she wants to make a monkey, once all the five parts are finished, she will glue them together, and then she will decorate it. 

The next day, if she wanted to make the same animal again, she needed to go over the same steps again and again. Finally she was tired of doing this, so she asked me if there is a copy machine that could help her to make a copy of her animals anytime she wants to have one. Well, it seems like Elizabeth also wants to follow the Do Not Repeat Yourself programming rules. 

So, it seems the prototype design pattern could satisfy Elizabeth's wish. In this case, Elizabeth can make a copy of her first animal (Prototype animal) and decorate it in different ways. She can also use her copied animal as prototype to make other animals as well.

Introduction

Prototype Design Pattern is also a pattern we use to receive an object instance for a particular class, such as builder and factory pattern. Instead of having a new fresh object every time, we can make a copy of an existed object instantly (object we can use as Prototype) and start using it. In that way, we do not have to repeat the building process for the object we are trying to use. The new copy object is totally independent with the original prototype object, and can be used for any purpose that will not affect the original. There is no limit for copying the existing objects, any existing object can be copied. This article introduces an implementation about how we use the Prototype Design Pattern for Elizabeth's animals.

Prototype Design Pattern Structure

Prototype.JPG

Class Diagram

PrototypeClass.JPG

Implementation Code

Prototype Objects

Animal

Animal class is a class that we are going to make cloneable. In C# .NET, we inherit ICloneable interface to make our class a cloneable class. In order to implement the clone() method, either shallow copy or deep copy could be used. Depends on what we need, we can also select different strategies to implement the shallow copy or deep copy too. However, if we do a shallow copy, all the reference variables in the class will still point the same address which the original prototype object has. The Animal class contains a constructor which accepts another Animal as a parameter, I code all the clone processes here so it can be called in its clone() method to achieve the ability to clone itself. Another way we could make the Animal to be cloneable is to use Serialize attribute to make the Animal class to be serializeable. We could serialize the current object to MemoryStream and deserialize it back to a new object as the copied object. Please read more details about how to make shallow copy and deep copy through the MSDN web site.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Animal : ICloneable
        {
            public Head AHead { get; set; }
            public List<leg> Legs { get; set; }
            public Tail ATail { get; set; }
            public string Name { get; set; }

            public Animal()
            {
                AHead = new Head();
                Legs = new List<leg>();
                ATail = new Tail();
            }

            //Constructor to implement the deep copy here
            public Animal(Animal aAnimal)
            {
                Name = aAnimal.Name;
                AHead = (Head)aAnimal.AHead.Clone();

                Legs = new List<leg>();
                foreach (Leg aLeg in aAnimal.Legs)
                {
                    Legs.Add((Leg)aLeg.Clone());
                }
                ATail = (Tail)aAnimal.ATail.Clone();
            }

            //Helper method to show the result from client
            public void Dispaly()
            {

                Console.WriteLine("I am a " + Name);
                AHead.Display();
                foreach (Leg aleg in Legs)
                {
                    aleg.Display();
                }
                ATail.Display();
                Console.WriteLine();
            }

            #region ICloneable Members
            //call deep coy to perform clone process
            public object Clone()
            {
                return new Animal(this);
            }

            #endregion
        }
    }
}

Head

Head class is another class that will be declared in our Animal class. Since it's a reference object in our Animal class, I also implement the Clone() method to make itself cloneable when we need to clone it. The difference from the Animal class is that I used MemberwiseClone() in Clone() method to copy itself. .NET MemberwiseClone() helps us to make a shallow copy of our object. Since I only have Number (int type) and Name (string is reference, but it's also an immutable type that can't be changed. So there is no difference whether I make a shallow copy or a deep copy for it) in my head class, the MemberwiseClone() should work just fine for it.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Head : ICloneable
        {
            public int Number { get; set; }
            public string Name { get; set; }


            public void Display()
            {
                Console.WriteLine("I have {0} {1} ", Number, Name);
            }

            #region ICloneable Members
            //create a shallow copy of current object 
            public object Clone()
            {
                return this.MemberwiseClone();
            }

            #endregion
        }
    }
}

Leg

Same as Head, Leg class also inherits ICloneable to make itself copied.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Leg : ICloneable
        {
            public string Side { get; set; }
            public string Name { get; set; }

            public void Display()
            {
                Console.WriteLine("This is my {0} {1} ", Side, Name);
            }

            #region ICloneable Members

            public object Clone()
            {
                return this.MemberwiseClone();
            }

            #endregion
        }
    }
}

Tail

Tail class is another cloneable class which is the same as Head.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace www.askbargains.com
{
    namespace PrototypeDesignPattern
    {
        public class Tail : ICloneable
        {
            public string Color { get; set; }

            public void Display()
            {
                Console.WriteLine("My tail is {0}", Color);
            }

            #region ICloneable Members

            public object Clone()
            {
                return this.MemberwiseClone();
            }

            #endregion
        }
    }
}

Client App

From the client side, Elizabeth will build the first animal object. After that, she will just make a copy of her first animal to play with.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using www.askbargains.com.PrototypeDesignPattern;

namespace www.askbargains.com
{
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                //Elizabeth starts building her first animal
                Animal firstAnimal = new Animal();

                firstAnimal.Name = "Deer";
                //work on head
                firstAnimal.AHead.Name = "Antlers";
                firstAnimal.AHead.Number = 2;

                Leg leftLeg = new Leg();
                leftLeg.Side = "Left";
                leftLeg.Name = "Hoove";

                Leg rightLeg = new Leg();
                rightLeg.Side = "Right";
                rightLeg.Name = "Hoove";

                firstAnimal.Legs.Add(leftLeg);
                firstAnimal.Legs.Add(rightLeg);

                firstAnimal.ATail.Color = "Brown";
                
                //Elizabeth copied the firstAnimal(prototype)
                Animal copiedAnimal =(Animal)firstAnimal.Clone();

                Console.WriteLine("Display the first animal");
                firstAnimal.Dispaly();        
                
                Console.WriteLine("Display the copied animal");
                copiedAnimal.Dispaly();

                //Elizabeth play aroud with the copiedAnimal
                copiedAnimal.Name = "Copied Deer";
                copiedAnimal.AHead.Name = "Antlers";
                copiedAnimal.AHead.Number = 1;
             
                //display the result
                Console.WriteLine("Display the copied animal after some play. 
				Elizabeh only made 1 antler for it");
                copiedAnimal.Dispaly();

                Console.WriteLine("Display the original prototype");
                firstAnimal.Dispaly();
                
                //Elizabeth make an other copy by using the copiedAnimal as the prototype
                Animal secondCopy = (Animal)copiedAnimal.Clone();
                secondCopy.Name = "An other copy";
                
                //Display the second copy
                Console.WriteLine("Display the secnod copy animal");
                secondCopy.Dispaly();
                Console.Read();
            }
        }
    }
}

Once we start our client app, you will see that the copied object is exactly the same as the prototype object (firstAnimal). Play with the copied object will not effect the original prototype. Cool.

Prototype_output.JPG

Conclusion

In this article, I demonstrated how we can use the Prototype Pattern to help us to copy an existing object. I also wrote another article for the Builder Design pattern about how to create an instance object. 

History

  • 23rd September, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)