Article Options
Premium Sponsor
Premium Sponsor

 »  Home  »  Windows Development  »  Prototype Pattern in C# and VB.NET
Prototype Pattern in C# and VB.NET
by Ashish Jaiman | Published  03/06/2002 | Windows Development | Rating:
Ashish Jaiman

Ashish works as a Sr. Software Developer with Lexign Inc., an end-to-end trusted electronic transaction management software provider (http://www.lexign.com).

Ashish has 6 years of experience in designing and developing distributed systems, server technologies and web based software applications using Microsoft technologies, Java, XML and .NET. He holds MCSD (Microsoft Certified Software Developer) and SCJP (Sun Certified Java Programmer) certifications.

Contact Ashish at jaimanalwar@yahoo.com or ashish.jaiman@lexign.com.

 

View all articles by Ashish Jaiman...
Prototype Pattern in C# and VB.NET

Article source code: prototype.zip

The Prototype pattern is used when creating an instance of a class is very time-consuming or complex in some way. Then, rather than creating more instances, you make copies of the original instance, modifying them as appropriate. Prototypes can also be used whenever you need classes that differ only in the type of processing they offer i.e. when there are many subclasses that differ only in the kind of objects they create a Prototype Pattern can be used to reduce the number of subclasses by cloning a prototype. Prototype Design Pattern helps in reducing number of classes.

In this pattern the catch is "Create objects by cloning". We sometimes create many subclasses that differ only in the kind of objects they create. In place of many subclasses creating different objects, we can have only one subclass that keeps reference to each object's base class and to create the object, clones the object passed as parameter to the constructor argument of the subclass. Each object implements the clone method so that it can be cloned. We can use Prototype pattern to reduce the number of subclasses by cloning a prototype.

Cloning can be achieved by implementing ICloneable of the System namespace. The only member of ICloneable interface is Clone method that returns a new instance of a class with the same value as an existing instance.

ICloneable.Clone method signature

[Visual Basic] Function Clone() As Object
[C#] object Clone();

We must understand that the Clone() method does a Shallow copy not Deep copy. So it just returns a reference to the original copy unlike in Deep copy where a duplicate instance is created. Any changes made to the clone will be reflected in the original copy and vice versa. We can implement Deep copy by using ISerializable interface. One other drawback is that each subclass of Prototype must implement Clone() method. For example, adding clone method may be difficult when classes under consideration already exist.

In the example I have created an EmpData class that implements ICloneable and ISerializable interfaces, ICloneable interface is required to mark the class as Cloneable and Clone method is implemented. ISerializable interface is used to implement deep copy (clone) for an EmpData Class, the trick I have used it to serialize the EmpData in a file and Deserialize the file and create another EmpData object, that would copy the Emp objects rather then copying their references as Clone method does.

The EmpData class has two methods GetEmpData and ChangeEmpData that will get the EmpData as a string and change the data of all the Emp classes. Each of the methods can be called and be used to verify the difference between shallow and deep cloning. In shallow cloning if the EmpData is changed then the changes also appear in the clone of the EmpData object, in deep copy once the EmpData object is cloned the changes would not appear in the clone if the data of the cloned object changes.

The construction of the EmpData is time consuming as it reads an XML File and creates Emp objects.

XML File

<employees>
    <employee>
        <firstname>ashish</firstname>
        <lastname>jaiman</lastname>
    </employee>
    <employee>
        <firstname>jaya</firstname>
        <lastname>pandey</lastname>
    </employee>
    <employee>
        <firstname>neeraj</firstname>
        <lastname>jaiman</lastname>
    </employee>
    <employee>
        <firstname>ashutosh</firstname>
        <lastname>sharma</lastname>
    </employee>
    <employee>
        <firstname>zerman</firstname>
        <lastname>billingslea</lastname>
    </employee>
    <employee>
        <firstname>bernd</firstname>
        <lastname>burkhardt</lastname>
    </employee>
    <employee>
        <firstname>sanjeev</firstname>
        <lastname>bhutt</lastname>
    </employee>
    <employee>
        <firstname>li</firstname>
        <lastname>li</lastname>
    </employee>
</employees>

C# Implementation

using System;
using System.Xml;
using System.IO;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable()]public class CEmpData: ICloneable,ISerializable
{
    private ArrayList ArrEmp;
    public CEmpData()
    {
        ArrEmp = new ArrayList();
        InitializeData();
    }
    private void InitializeData()
    {
        XmlDocument xmlDoc = new XmlDocument();
        CEmp objEmp;
        xmlDoc.Load("empdata.xml");
        foreach(XmlNode node in xmlDoc.DocumentElement.ChildNodes)
        {
            objEmp = new CEmp();
            objEmp.FName = node.SelectSingleNode("firstname").InnerText;
            objEmp.LName = node.SelectSingleNode("lastname").InnerText;
            ArrEmp.Add (objEmp);
        }
    }

    public CEmpData(SerializationInfo info,StreamingContext context)
    {
        int intCount=0;
        CEmp objEmp;
        ArrEmp = new ArrayList();
        intCount = (int)info.GetValue("emp_count", intCount.GetType());
        for (int intIndex = 0;intIndex<intCount;intIndex++)
        {
            objEmp = new CEmp(info,context,intIndex);
            ArrEmp.Add(objEmp);
        }
    }

    public void GetObjectData(SerializationInfo info,StreamingContext context)
    {
        CEmp objEmp;
        info.AddValue("emp_count", ArrEmp.Count);
        for (int intIndex = 0;intIndex<ArrEmp.Count ;intIndex++)
        {
            objEmp = (CEmp)ArrEmp[intIndex];
            objEmp.GetObjectData(info,context,intIndex);
        }
    }


    public object Clone()
    {
        return this;
    }

    public object Clone(bool Deep)
    {
        if(Deep)
            return CreateDeepCopy();
        else
            return Clone();
    }

    private CEmpData CreateDeepCopy()
    {
        CEmpData objEmpCopy;
        Stream objStream;
        BinaryFormatter objBinFormatter = new BinaryFormatter();
        try
        {
            objStream = File.Open("Empdata.bin", FileMode.Create);
            objBinFormatter.Serialize(objStream, this);
            objStream.Close();

            objStream = File.Open("Empdata.bin", FileMode.Open);
            objEmpCopy = (CEmpData)objBinFormatter.Deserialize(objStream);
            objStream.Close();
            return objEmpCopy;
        }
        catch(Exception ex)
        {
            Console.WriteLine (ex.ToString());
            return null;
        }
    }

    public string GetEmpData()
    {
        string strEmpData="";
        for (int intCount = 0;intCount < ArrEmp.Count;intCount++)
        {
            strEmpData = strEmpData + ((CEmp)ArrEmp[intCount]).FName +
                         "\t" + ((CEmp)ArrEmp[intCount]).LName  + "\n";
        }
        return strEmpData;
    }

    public void ChangeEmpData()
    {
        foreach (CEmp objEmp in ArrEmp)
        {
            objEmp.FName ="FirstName";
            objEmp.LName ="LastName";
        }
    }
}

using System;
using System.Runtime.Serialization;

public class CEmp
{
    private string mstrFName;
    private string mstrLName;

    public string FName
    {
        get
        {
            return mstrFName;
        }
        set
        {
            mstrFName = value;
        }
    }

    public string LName
    {
        get
        {
            return mstrLName;
        }
        set
        {
            mstrLName = value;
        }
    }

    public CEmp()
    {

    }

    public CEmp(SerializationInfo info, StreamingContext context, int intIndex)
    {    string temp = "temp";
        mstrFName = (string)info.GetValue("emp_fname"
                    + intIndex,temp.GetType());
        mstrLName = (string)info.GetValue("emp_lname"
                    + intIndex, temp.GetType());
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context,
        int intIndex)
    {
        info.AddValue("emp_fname" + intIndex, mstrFName);
        info.AddValue("emp_lname" + intIndex, mstrLName);
    }
}

VB.NET Implementation

Imports System.Xml
Imports System.IO
Imports System.Collections
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

<Serializable()> Public Class CEmpData
    Implements ICloneableISerializable
    Private ArrEmp As ArrayList

    Public Sub New()
        Dim xmldoc As New XmlDocument()
        Dim node As XmlNode
        Dim objEmp As CEmp
        ArrEmp = New ArrayList()
        xmldoc.Load("empdata.xml")
        For Each node In xmldoc.DocumentElement.ChildNodes
            objEmp = New CEmp()
            objEmp.FName = node.SelectSingleNode("firstname").InnerText
            objEmp.LName = node.SelectSingleNode("lastname").InnerText
            ArrEmp.Add(objEmp)
        Next
    End Sub

    Public Sub New(ByVal info As SerializationInfo_
        ByVal context As StreamingContext)
        Dim intIndex As Integer
        Dim intCount As Integer
        Dim objEmp As CEmp
        ArrEmp = New ArrayList()
        intCount = CInt(info.GetValue("emp_count"GetType(String)))
        For intIndex = 0 To intCount - 1
            objEmp = New CEmp(infocontextintIndex)
            ArrEmp.Add(objEmp)
        Next
    End Sub

    Public Function Clone() As Object Implements ICloneable.Clone
        Try
            Return Me
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Function

    Public Function Clone(ByVal Deep As BooleanAs Object
        Try
            If Deep Then
                Return CreateDeepCopy()
            Else
                Return Clone()
            End If
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Function

    Private Function CreateDeepCopy() As CEmpData
        Dim objEmpCopy As CEmpData
        Dim objStream As Stream
        Dim objBinFormatter As New BinaryFormatter()
        Try
            objStream = File.Open("Empdata.bin"FileMode.Create)
            objBinFormatter.Serialize(objStreamMe)
            objStream.Close()
            objStream = File.Open("Empdata.bin"FileMode.Open)
            objEmpCopy = CType(objBinFormatter.Deserialize(objStream), _
                CEmpData)
            objStream.Close()
            CreateDeepCopy = objEmpCopy
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Function

    Public Sub GetObjectData_
        ByVal info As System.Runtime.Serialization.SerializationInfo_
        ByVal context As System.Runtime.Serialization.StreamingContext_
        Implements System.Runtime.Serialization.ISerializable.GetObjectData
        Dim intIndex As Integer
        Dim objEmp As CEmp
        info.AddValue("emp_count"ArrEmp.Count)
        For intIndex = 0 To ArrEmp.Count - 1
            objEmp = ArrEmp(intIndex)
            objEmp.GetObjectData(infocontextintIndex)
        Next
    End Sub

    Public Function GetEmpData() As String
        Dim intCount As Integer
        Dim strEmpData As String
        For intCount = 0 To ArrEmp.Count - 1
            strEmpData = strEmpData & CType(ArrEmp(intCount), _
                CEmp).FName & Chr(9& CType(ArrEmp(intCount), _
                CEmp).LName & Chr(13)
        Next
        GetEmpData = strEmpData
    End Function

    Public Sub ChangeEmpData()
        Dim objEmp As CEmp
        For Each objEmp In ArrEmp
            objEmp.FName = "FirstName"
            objEmp.LName = "LastName"
        Next
    End Sub
End Class

Imports System.Runtime.Serialization

Public Class CEmp
    Private mstrFName As String
    Private mstrLName As String

    Public Property FName() As String
        Get
            FName = mstrFName
        End Get
        Set(ByVal Value As String)
            mstrFName = Value
        End Set
    End Property

    Public Property LName() As String
        Get
            LName = mstrLName
        End Get
        Set(ByVal Value As String)
            mstrLName = Value
        End Set
    End Property

    Public Sub New()
        
    End Sub

    Public Sub New(ByVal info As SerializationInfo_
        ByVal context As StreamingContextByVal intIndex As Integer)
        mstrFName = CStr(info.GetValue("emp_fname" & intIndex_
            GetType(String)))
        mstrLName = CStr(info.GetValue("emp_lname" & intIndex_
            GetType(String)))
    End Sub

    Public Sub GetObjectData(ByVal info As SerializationInfo_
        ByVal context As StreamingContextByVal intIndex As Long)
        info.AddValue("emp_fname" & intIndexmstrFName)
        info.AddValue("emp_lname" & intIndexmstrLName)
    End Sub

End Class
Generated using PrettyCode.Encoder
How would you rate the quality of this article?
1 2 3 4 5
Poor Excellent
Tell us why you rated this way (optional):

Article Rating
The average rating is: No-one else has rated this article yet.

Article rating:2.94999999999999 out of 5
 60 people have rated this page
Article Score36847
Sponsored Links