Prototype Design Pattern

Prototype Pattern –

This pattern is a type of creational pattern. It provides an efficient approach of creating shallow copies. Cloning on objects is prototype pattern. Limits number of object creation instances. It helps in reducing number of sub class instances. When we are not in a position to call the constructor of any child object we could use this pattern.  Any class, which wants to support cloning, should inherit from the ICloneable interface in C#. ICloneable interface contains a Clone() method which we can override in our class. This pattern can be used when creating an instance of class is more complex and time consuming.

Clone() method does a shallow copy and not deep copy. Shallow copy does reference to the original copy. Any changes made to the cone will be reflected in the original copy.

ICloneable interface is required to mark the class as Cloneable and Clone method is implemented. Prototype doesn't require subclassing, but it does require an "initialize" operation.  Scenario in which this pattern should be used is when we have to replace an original object with modified values and pass the same original object to perform other operations and can be used for comparison with modified and original values also.

It gives us a way to create new objects from the existing instance of the object. In one sentence we clone the existing object with its data. By cloning any changes to the cloned object does not affect the original object value. If you are thinking by just setting objects we can get a clone then you have mistaken it. By setting one object to other object we set the reference of object BYREF.  So changing the new object also changed the original object.

If Child objects have to be shallow copied then the child objects should also MemberWiseClone.  My experience suggests DTO's/Type DataSet should have Clone object

One is the shallow cloning which you have just read in the first question.  In shallow copy only that object is cloned, any objects containing in that object is not cloned.  For instance consider the figure ‘Deep cloning in action' we have a customer class and we have an address class aggregated inside the customer class. ‘MemberWiseClone' will only clone the customer class ‘ClsCustomer' but not the ‘ClsAddress' class. So we added the ‘MemberWiseClone' function in the address class also. Now when we call the ‘getClone' function we call the parent cloning function and also the child cloning function, which leads to cloning of the complete object. When the parent objects are cloned with their containing objects it's called as deep cloning and when only the parent is clones its termed as shallow cloning. There are many instances when we want the new copy object changes should not affect the old object. The answer to this is prototype patterns.

Sections in Prototype Pattern

1.       Prototype Class

2.       Concrete Class

3.       Client – Creates a new object using the clone property of concrete class

Diagram - Example 1

Diagram - Example 2

Sample Code – Example 1

 

namespace PrototypePattern

{

    public class UserRoleDTO

    {

        int userRoleID;

 

        public int UserRoleID

        {

            get { return userRoleID; }

            set { userRoleID = value; }

        }

 

        UserDTO userDTO;

 

        public UserDTO UserDTO

        {

            get { return userDTO; }

            set { userDTO = value; }

        }

        RoleDTO roleDTO;

 

        public RoleDTO RoleDTO

        {

            get { return roleDTO; }

            set { roleDTO = value; }

        }

 

        internal UserRoleDTO Clone()

        {

            return (UserRoleDTO)this.MemberwiseClone();

        }

    }

}

 

 

namespace PrototypePattern

{

    public class UserDTO

    {

        public UserDTO()

        {

 

        }

 

        private string userFirstName;

 

        public string UserFirstName

        {

            get { return userFirstName; }

            set { userFirstName = value; }

        }

        private string userShortName;

 

        public string UserShortName

        {

            get { return userShortName; }

            set { userShortName = value; }

        }

        private string userLoginID;

 

        public string UserLoginID

        {

            get { return userLoginID; }

            set { userLoginID = value; }

        }

 

        private UserRoleDTO userRoleDTO;

 

        internal UserRoleDTO UserRoleDTO

        {

            get { return userRoleDTO; }

            set { userRoleDTO = value; }

        }

 

        /// <summary>

        /// Prepares Shallow Copy of the Object

        /// </summary>

        /// <returns></returns>

        public UserDTO Clone()

        {

            return (UserDTO)this.MemberwiseClone();

        }

    }

}

 

namespace PrototypePattern

{

    public class RoleDTO

    {

        private int roleID;

 

        public int RoleID

        {

            get { return roleID; }

            set { roleID = value; }

        }

        private string roleName;

 

        public string RoleName

        {

            get { return roleName; }

            set { roleName = value; }

        }

        private string roleType;

 

        public string RoleType

        {

            get { return roleType; }

            set { roleType = value; }

        }

 

        public RoleDTO Clone()

        {

            return (RoleDTO)this.MemberwiseClone();

        }

    }

}

 

Sample Code – Example 2

 

using System;

 

namespace PrototypePattern

{

    class Client

    {

        public void ShallowCopy()

        {

            ConcretePrototypeA concretePrototypeA = new ConcretePrototypeA("A");

            ConcretePrototypeA concreatePrototypeC = (ConcretePrototypeA)concretePrototypeA.Clone();

 

            Console.WriteLine("Cloned: {0}", concreatePrototypeC.Id);

 

            concreatePrototypeC.Id = "C";

            Console.WriteLine("Cloned: {0}", concreatePrototypeC.Id);

            Console.WriteLine("Cloned: {0}", concretePrototypeA.Id);

 

            ConcretePrototypeB concretePrototypeB = new ConcretePrototypeB("B");

            ConcretePrototypeB concreatePrototypeD = (ConcretePrototypeB)concretePrototypeB.Clone();

 

            Console.WriteLine("Cloned: {0}", concreatePrototypeD.Id);

 

            concreatePrototypeD.Id = "D";

            Console.WriteLine("Cloned: {0}", concreatePrototypeD.Id);

            Console.WriteLine("Cloned: {0}", concretePrototypeB.Id);

        }

    }

}

 

 

namespace PrototypePattern

{

    public abstract class AbsPrototype

    {

        #region << Properties >>

        /// <summary>

        ///

        /// </summary>

        /// <returns></returns>

        private string id;

 

        /// <summary>

        ///

        /// </summary>

        public string Id

        {

            get { return id; }

            set { id = value; }

        }

        #endregion

 

        #region << Constructor >>

        public AbsPrototype() { }

        public AbsPrototype(string id)

        {

            this.Id = id;

        }

        #endregion

 

        #region ICloneable Members

 

        public abstract AbsPrototype Clone();

 

        #endregion

    }

}

namespace PrototypePattern

{

    public class ConcretePrototypeA : PrototypePattern.AbsPrototype

    {

        public ConcretePrototypeA(string id) : base(id) { }

 

        public override AbsPrototype Clone()

        {

            return (PrototypePattern.AbsPrototype)this.MemberwiseClone();

        }

    }

}

namespace PrototypePattern

{

    public class ConcretePrototypeB:PrototypePattern.AbsPrototype

    {

        public ConcretePrototypeB(string id) : base(id) { }

 

        public override AbsPrototype Clone()

        {

            return (PrototypePattern.AbsPrototype)this.MemberwiseClone();

        }

    }

}