我读设计模式之原型模式(Prototype Pattern)
引入 开发过程中,有时候需要创建多个同类型的对象。按照通常的思维,我们只是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模式同工厂模式,同样对客户隐藏了对象的创建工作,但是,与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的,达到了“隔离类对象的使用者和具体类型(易变类)之间的耦合关系”的目的。
学习参考:


浙公网安备 33010602011771号