开发过程中,有时候需要创建多个同类型的对象。按照通常的思维,我们只是new多个对象即可。但是如果这个对象的初始化是个耗时的过程,那么多个对象的创建将很难令人接受。
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
读了这个原型模式,感觉不像是在讲什么模式,倒像是在讲述一种应用,一种关于Clone的应用。
引入 开发过程中,有时候需要创建多个同类型的对象。按照通常的思维,我们只是new多个对象即可。但是如果这个对象的初始化是个耗时的过程,那么多个对象的创建将很难令人接受。
原型模式的用意是:通过给出一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的办法创建出更多的同类型对象。
C#中可以使用Clone()方法轻松实现对象拷贝,达到原型模式的目的。但是现在涉及一个概念:浅拷贝(shallow copy)深拷贝(deep Copy).区别两种拷贝方式,并实现具体作业,应该是原型模式实现的重点环节。
概念
(CLR via C#): 浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。
例证
浅拷贝
浅拷贝,实现ICloneable接口的Clone方法,使用object对象的MemberwiseClone()方法就可以实现。
namespace Demo1
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
class Program
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
static void Main(string[] args)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
clswork clsA = new clswork("1001");
clsA.setfiled("Ivan");
clsA.setaddress("XX");
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
clswork clsB = clsA.Clone() as clswork;
clsB.setfiled("Yan");
clsB.setaddress("ZZ");
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
clsA.display();
clsB.display();
}
}
class clswork:ICloneable
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private string _id;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Id
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _id; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _id = value; }
}
private string _name;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Name
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _name; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _name = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private mycls clstest=new mycls();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public clswork(string id)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this._id = id;
}
public void setaddress(string add)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
clstest.address = add;
}
public void setfiled(string name)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this._name = name;
}
public void display()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("The id is:{0},the name is: {1},the address is: {2}",Id,Name,clstest.address);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public object Clone()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.MemberwiseClone();
}
}
class mycls
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace Demo1
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
class App
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
static void Main()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ConcretePrototype c1 = new ConcretePrototype("1001", "ivan");
c1.SetAdd("深圳");
c1.show();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ConcretePrototype c2 = c1.Clone() as ConcretePrototype;
c2.SetAdd("广州");
c2.show();
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[Serializable] //可序列化
public abstract class Prototype
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
public abstract Prototype Clone();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[Serializable] //可序列化
class ConcretePrototype : Prototype
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private string id;
private string name;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private workAdd workadd;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Id
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return id; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ id = value; }
}
public string Name
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return name; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ name = value; }
}
public void SetAdd(string address)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
workadd.Address = address;
}
public ConcretePrototype(string id, string name)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.id = id;
this.name = name;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
workadd = new workAdd();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public void show()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("id is {0},name is {1},address is {2}", Id, Name, workadd.Address);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override Prototype Clone() //重写Clone方法
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Prototype MyPrototype;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
MemoryStream memoryStream = new MemoryStream();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
BinaryFormatter formatter = new BinaryFormatter();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
formatter.Serialize(memoryStream, this);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
memoryStream.Position = 0;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
MyPrototype = (Prototype)formatter.Deserialize(memoryStream);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return MyPrototype;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[Serializable] //可序列化
class workAdd
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private string address;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Address
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return address; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ address = value; }
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
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;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace Demo1
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
class App
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
static void Main()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ConcretePrototype c1 = new ConcretePrototype("1001", "ivan");
c1.SetAdd("henan");
c1.show();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ConcretePrototype c2 = c1.Clone() as ConcretePrototype;
c2.SetAdd("shandong");
c2.show();
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public abstract class Prototype
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
public abstract Prototype Clone();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
class ConcretePrototype : Prototype
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private string id;
private string name;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private workAdd workadd;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Id
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return id; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ id = value; }
}
public string Name
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return name; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ name = value; }
}
public void SetAdd(string address)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
workadd.Address = address;
}
public ConcretePrototype(string id, string name)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.id = id;
this.name = name;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
workadd = new workAdd();
}
public ConcretePrototype(workAdd work)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.workadd = work.Clone() as workAdd;
}
public void show()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.WriteLine("id is {0},name is {1},address is {2}", Id, Name, workadd.Address);
}
public override Prototype Clone()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ConcretePrototype c = new ConcretePrototype(workadd);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
c.Id = id;
c.name = name;
return c;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
}
}
class workAdd : ICloneable
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
private string address;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public string Address
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return address; }
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ address = value; }
}
public object Clone()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return this.MemberwiseClone();
}
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
总结 Prototype模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了“隔离类对象的使用者和具体类型(易变类)之间的耦合关系”的目的。
学习参考:
http://www.cnblogs.com/Ivan-Yan/admin/EditPosts.aspx?opt=1
http://www.cnblogs.com/zhenyulu/articles/39257.aspx