什么是原型模式?
原型模式是一种对象创建型模式,它将一个原型对象传递给一个要发起创建的对象,该对象通过请求原型对象复制自己来实现创建过程。
由于软件系统中经常会出现需要创建多个相同或相似的对象,因此原型模式在开发中具有较高的使用频率。通过原型模式克隆出来的对象属于全新的对象,它们在内存中拥有自己的内存地址,对克隆对象的修改不会影响原型对象,并且每一个克隆对象都是相互独立的。
浅克隆与深克隆
浅克隆
在浅克隆中,如果原型对象的成员变量是值类型,将会复制一份给克隆对象;如果成员变量是引用类型,则将引用类型的地址复制一份给克隆对象,也就是说克隆对象与原型对象的成员变量指向相同的内存地址。即浅克隆的时候,只复制原型对象本身和它的值类型成员,而引用类型的成员并没有复制。
深克隆
深克隆的时候,原型对象中的值类型成员和引用类型成员都将复制给克隆对象,即深克隆除了复制对象本身以外,对象所包含的所有成员也将被复制。
原型模式的结构
- ProtoType(抽象原型类):声明克隆方法的接口,所有具体原型类的父类,可以是抽象类或者接口。
- ProtoTypeA(具体原型类):继承自ProtoType并实现克隆方法,在克隆方法中返回一个自己的克隆对象。
- Client(使用类):使用的时候让一个原型对象克隆自身创建一个新的对象,只需要创建出一个原型对象,就可以通过调用原型对象的克隆方法即可得到多个相同的对象。
原型模式的实现
abstract class ProtoType
{
public abstract ProtoType Clone();
}
class ProtoTypeA : ProtoType
{
private string m_Attr;
public string Attr
{
get
{
return this.m_Attr;
}
set
{
this.m_Attr = value;
}
}
public override ProtoType Clone()
{
var o = new ProtoTypeA();
o.Attr = this.m_Attr;
return o;
}
}
static void Main()
{
//使用
var prototypeA = new ProtoTypeA();
var copy = prototypeA.Clone();
}
C#的MemberwiseClone方法
在C#语言中,提供了MemberwiseClone方法用于实现浅克隆,修改代码如下:
class ProtoTypeA : ProtoType
{
private string m_Attr;
public string Attr
{
get
{
return this.m_Attr;
}
set
{
this.m_Attr = value;
}
}
private Member m_Member;
public Member Member
{
get
{
return this.m_Member;
}
set
{
this.m_Member = value;
}
}
public override ProtoType Clone()
{
return (ProtoTypeA)this.MemberwiseClone();
}
}
调用以下代码证明为浅克隆
static void Main()
{
var prototypeA = new ProtoTypeA();
var copy = (ProtoTypeA)prototypeA.Clone();
Console.WriteLine(prototypeA == copy); //false
Console.WriteLine(prototypeA.Attr == copy.Attr); //true
Console.WriteLine(prototypeA.Member == copy.Member); //true,证明为浅克隆
Console.ReadKey();
}
修改代码实现深克隆
public override ProtoType Clone()
{
var copy = (ProtoTypeA)this.MemberwiseClone();
copy.Member = new Member();
return copy;
}
static void Main()
{
var prototypeA = new ProtoTypeA();
var copy = (ProtoTypeA)prototypeA.Clone();
Console.WriteLine(prototypeA == copy); //false
Console.WriteLine(prototypeA.Attr == copy.Attr); //true
Console.WriteLine(prototypeA.Member == copy.Member); //false,证明为深克隆
Console.ReadKey();
}
序列化实现深克隆
[Serializable]
abstract class ProtoType
{
public abstract ProtoType Clone();
}
[Serializable]
class Member { }
[Serializable]
class ProtoTypeA : ProtoType
{
...
}
修改Clone方法
public override ProtoType Clone()
{
ProtoTypeA copy = null;
using (var fs = new FileStream("Temp.txt", FileMode.Create))
{
try
{
new BinaryFormatter().Serialize(fs, this);
}
catch (SerializationException e)
{
throw e;
}
}
using (var fs = new FileStream("Temp.txt", FileMode.Open))
{
try
{
copy = (ProtoTypeA)new BinaryFormatter().Deserialize(fs);
}
catch (SerializationException e)
{
throw e;
}
};
return copy;
}
static void Main()
{
var prototypeA = new ProtoTypeA();
prototypeA.Member = new Member();
var copy = (ProtoTypeA)prototypeA.Clone();
Console.WriteLine(prototypeA == copy); //false
Console.WriteLine(prototypeA.Attr == copy.Attr); //true
Console.WriteLine(prototypeA.Member == copy.Member); //false,证明为深克隆
Console.ReadKey();
}
原型模式的优点&缺点
优点
- 如果要创建的对象实例较为复杂,使用原型模式可以简化对象的创建过程,提高新实例的创建效率。
- 较好的扩展性,原型模式中提供了抽象原型类,针对抽象编程,可将具体原型类写入配置文件。
- 简化了创建结构,与工厂方法模式不同,无需专门的工厂类来创建对象。
- 可以使用深克隆的方法保存对象的状态,使用原型模式将对象复制一份并将其状态保存,以便在需要用的时候使用,例如恢复到某一历史状态。
缺点
- 实现深克隆时需要编写较为复杂的代码,当对象之间存在多重嵌套引用时,每一层对象都必须支持深克隆,实现起来会比较麻烦,增加系统理解难度。
适合使用原型模式的场景
- 创建对象成本较大(耗时长、占用CPU资源或网络资源大),新对象可以通过复制已有对象获得,若是相似对象,则可以修改其成员变量即可。
- 系统需要保存对象的状态。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。