开发过程中,有时候需要创建多个同类型的对象。按照通常的思维,我们只是new多个对象即可。但是如果这个对象的初始化是个耗时的过程,那么多个对象的创建将很难令人接受。
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
读了这个原型模式,感觉不像是在讲什么模式,倒像是在讲述一种应用,一种关于Clone的应用。
引入 开发过程中,有时候需要创建多个同类型的对象。按照通常的思维,我们只是new多个对象即可。但是如果这个对象的初始化是个耗时的过程,那么多个对象的创建将很难令人接受。
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
C#中可以使用Clone()方法轻松实现对象拷贝,达到原型模式的目的。但是现在涉及一个概念:浅拷贝(shallow copy)深拷贝(deep Copy).区别两种拷贝方式,并实现具体作业,应该是原型模式实现的重点环节。
概念
(CLR via C#): 浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。
例证
浅拷贝
浅拷贝,实现ICloneable接口的Clone方法,使用object对象的MemberwiseClone()方法就可以实现。
namespace Demo1


{
class Program

{
static void Main(string[] args)

{
clswork clsA = new clswork("1001");
clsA.setfiled("Ivan");
clsA.setaddress("XX");

clswork clsB = clsA.Clone() as clswork;
clsB.setfiled("Yan");
clsB.setaddress("ZZ");

clsA.display();
clsB.display();
}
}
class clswork:ICloneable

{
private string _id;

public string Id

{

get
{ return _id; }

set
{ _id = value; }
}
private string _name;

public string Name

{

get
{ return _name; }

set
{ _name = value; }
}

private mycls clstest=new mycls();

public clswork(string id)

{
this._id = id;
}
public void setaddress(string add)

{
clstest.address = add;
}
public void setfiled(string name)

{
this._name = name;
}
public void display()

{
Console.WriteLine("The id is:{0},the name is: {1},the address is: {2}",Id,Name,clstest.address);
}

public object Clone()

{
return this.MemberwiseClone();
}
}
class mycls

{
public string address = "test";
}
}
执行结果:
The id is:1001,the name is: Ivan,the address is: ZZ
The id is:1001,the name is: Yan,the address is: ZZ
Press any key to continue . . .
可以看到,浅拷贝,对于引用类型的拷贝是无效的,或者说引用类型的数据段不会被拷贝。这样的话,新建立的对象和原型对象中引用类型对象都指向同一个对象,所以新对象的修改,必然影响到原型对象。
要想使新对象和原型对象互不影响,必须使用深拷贝。实现深拷贝必须手动重写Clone方法,可以使用序列化实现。(注意抽象原型对象和具体对象都要标记为可序列化)
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Demo1


{
class App

{
static void Main()

{
ConcretePrototype c1 = new ConcretePrototype("1001", "ivan");
c1.SetAdd("深圳");
c1.show();

ConcretePrototype c2 = c1.Clone() as ConcretePrototype;
c2.SetAdd("广州");
c2.show();
}
}

[Serializable] //可序列化
public abstract class Prototype

{
public abstract Prototype Clone();
}

[Serializable] //可序列化
class ConcretePrototype : Prototype

{
private string id;
private string name;

private workAdd workadd;

public string Id

{

get
{ return id; }

set
{ id = value; }
}
public string Name

{

get
{ return name; }

set
{ name = value; }
}
public void SetAdd(string address)

{
workadd.Address = address;
}
public ConcretePrototype(string id, string name)

{
this.id = id;
this.name = name;

workadd = new workAdd();
}

public void show()

{
Console.WriteLine("id is {0},name is {1},address is {2}", Id, Name, workadd.Address);
}

public override Prototype Clone() //重写Clone方法

{
Prototype MyPrototype;

MemoryStream memoryStream = new MemoryStream();

BinaryFormatter formatter = new BinaryFormatter();

formatter.Serialize(memoryStream, this);

memoryStream.Position = 0;

MyPrototype = (Prototype)formatter.Deserialize(memoryStream);

return MyPrototype;
}
}

[Serializable] //可序列化
class workAdd

{
private string address;

public string Address

{

get
{ return address; }

set
{ address = value; }
}

}
}
id is 1001,name is ivan,address is 深圳
id is 1001,name is ivan,address is 广州
Press any key to continue . . .
实现深拷贝,还有另外一种做法:
using System;
using System.Collections.Generic;
using System.Text;

namespace Demo1


{
class App

{
static void Main()

{
ConcretePrototype c1 = new ConcretePrototype("1001", "ivan");
c1.SetAdd("henan");
c1.show();

ConcretePrototype c2 = c1.Clone() as ConcretePrototype;
c2.SetAdd("shandong");
c2.show();
}
}

public abstract class Prototype

{
public abstract Prototype Clone();
}

class ConcretePrototype : Prototype

{
private string id;
private string name;

private workAdd workadd;

public string Id

{

get
{ return id; }

set
{ id = value; }
}
public string Name

{

get
{ return name; }

set
{ name = value; }
}
public void SetAdd(string address)

{
workadd.Address = address;
}
public ConcretePrototype(string id, string name)

{
this.id = id;
this.name = name;

workadd = new workAdd();
}
public ConcretePrototype(workAdd work)

{
this.workadd = work.Clone() as workAdd;
}
public void show()

{
Console.WriteLine("id is {0},name is {1},address is {2}", Id, Name, workadd.Address);
}
public override Prototype Clone()

{
ConcretePrototype c = new ConcretePrototype(workadd);

c.Id = id;
c.name = name;
return c;

}
}
class workAdd : ICloneable

{
private string address;

public string Address

{

get
{ return address; }

set
{ address = value; }
}
public object Clone()

{
return this.MemberwiseClone();
}
}
}
总结 Prototype模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了“隔离类对象的使用者和具体类型(易变类)之间的耦合关系”的目的。
学习参考:
http://www.cnblogs.com/Ivan-Yan/admin/EditPosts.aspx?opt=1
http://www.cnblogs.com/zhenyulu/articles/39257.aspx