网站首页/技术开发列表/内容

完成Prototype设计模式

技术开发2022-04-27阅读
实现Prototype设计模式

Implementing the Prototype design Pattern



当我建立一个类的实例很复杂时,我们可以使用Prototype模式。与其建立很多类的实例,还不如进行适当的修改后,使用最初的实例的副本。使用Prototype模式,可以通过克隆一个原型,减少子类的数量。Prototype模式可以减少类的实例的数量。

在这个模式中,通过克隆来创建对象。我们有时创建很多的子类,除了通过很多的子类来创建不同的对象,我们还可以只需要唯一的一个子类,这个子类保持对每个对象基类的引用,并通过这个子类创建对象。通过向子类的构造函数传递参数并克隆对象。每个对象都实现clone方法,所以可以被克隆。我们可以使用Prototype模式,通过克隆原型来减少子类的数量。

克隆可以通过实现Icloneable接口来实现。Icloneable接口中唯一的方法是Clone,并返回一个新的类的实例。

ICloneable.Clone method signature
[VisualBasic] Function Clone() As Object
[C#] object Clone();




我们必须了解Clone()方法只是一种浅表复制(Shallow copy),而不是深层复制(Deep copy)。所以它只是返回一个引用,而不象深层复制(Deep copy)那样创建一个复制的实例。我们可以通过使用Iserializable接口来实现深层复制(Deep copy)。

另一个缺点就是原型的每个子类必须实现Clone()方法,有时候,增加clone方法是很困难的。

在这个例子中,我建立了EmpData类,并且实现了Icloneable接口和Iserializable接口。Icloneable接口需要实现Clone方法,使得类可以被复制。Iserializable接口为了实现对EmpData类的深层复制(Deep copy)。使用的方法为:将EmpData对象序列化为一个文件,也可以将这个文件反序列化为一个EmpData对象。

EmpData类包含两个方法:GetEmpData和ChangeEmpData。这两个方法被用来以一个字符串(string)的形式获取EmpData对象、更改EmpData类。每个方法都可以被调用,来检验浅表复制(Shallow copy)和深层复制(Deep copy)的不同。浅表复制(Shallow copy)时,如果EmpData类改变时,这个变化也会同时出现在EmpData的克隆对象中;而在深层复制(Deep copy),如果EmpData对象发生改变时,这个变化不会出现在EmpData的克隆对象中。

EmpData类的构造函数读取XML文件并创建Emp对象。

XML 文件




VB.Net 实现



Imports System.Xml

Imports System.IO

Imports System.Collections

Imports System.Runtime.Serialization

Imports System.Runtime.Serialization.Formatters.Binary

<Serializable()> Public Class CEmpData

Implements ICloneable, ISerializable

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(info, context, intIndex)

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 Boolean) As 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(objStream, Me)

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(info, context, intIndex)

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

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 StreamingContext, ByVal 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 StreamingContext, ByVal intIndex As Long)

info.AddValue("emp_fname" & intIndex, mstrFName)

info.AddValue("emp_lname" & intIndex, mstrLName)

End Sub

End Class

……

相关阅读