一. 原型模式简介
原型模式(Prototype Pattern)也是一种创建型模式,它关注的是大量相似对象的创建问题。我们经常会遇到这样的情况:在系统中要创建大量的对象,这些对象之间具有几乎完全相同的功能,只是在细节上有一点儿差别。
这样的情形经常遇到。三国系列游戏是我最喜欢的游戏系列之一。你有没有注意到那里边上百位英雄的头像基本上很相似?你仔细区分就会发现,虽然每个人都不同,但基本上只具有几种脸型:长方的、圆形的、细长的,然后配上不同的胡子、眉毛、眼睛、嘴,有的再加点儿伤疤或装饰物(比如给独眼龙夏侯敦加个单眼罩),就成了不同的人物头像!那么,为什么会这样的?因为根据研究表明,人类的脸谱基本上只有有限的几个类型,只不过在细节和组合方面存在些许差异。游戏制作者具有依据这个理论,只对人脸进行有限的几种建模,然后再通过组合、修饰,就可以产生无数的头像了。
用面向对象的方法来说就是,我们先建立一个原型,然后通过对原型进行复制和修饰的方法,就可以产生一个和原型相似的新对象。用GoF的话来说就是:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
{
// 抽象钥匙原型
public abstract class Key
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string owner;
public string Owner
{
get { return owner; }
set { owner = value; }
}
public Key( string name, string owner)
{
this .name = name;
this .owner = owner;
}
// 钥匙复制自身的抽象定义
public abstract Key Clone();
public override String ToString()
{
return this .Name + " , belongs to " + this .Owner;
}
}
// 大门钥匙
public class GateKey : Key
{
public GateKey( string owner) : base ( " Gate Key " , owner) { }
public override Key Clone()
{
return new GateKey( this .Owner);
}
}
// 橱柜钥匙
public class CabinetKey : Key
{
public CabinetKey( string owner) : base ( " Cabinet Key " , owner) { }
public override Key Clone()
{
return new CabinetKey( this .Owner);
}
}
// 客户调用方法
public class Client
{
public static void Main( string [] args)
{
Key oldGateKey, newGateKey, oldCabinetKey, newCabinetKey;
oldGateKey = new GateKey( " GF " );
newGateKey = oldGateKey.Clone();
newGateKey.Owner = " Me " ;
oldCabinetKey = new CabinetKey( " Me " );
newCabinetKey = oldCabinetKey.Clone();
newCabinetKey.Owner = " GF " ;
Console.WriteLine(oldGateKey);
Console.WriteLine(newGateKey);
Console.WriteLine(oldCabinetKey);
Console.WriteLine(newCabinetKey);
}
}
}
1. Clone()方法
2 . 深复制和浅复制
{
public GateKey( string owner) : base ( " Gate Key " , owner) { }
public override Key Clone()
{
return (Key) this .MemberwiseClone();
}
}
3. 原型管理器
{
// 抽象钥匙原型
[Serializable]
public abstract class Key : ICloneable
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string owner;
public string Owner
{
get { return owner; }
set { owner = value; }
}
public Key( string name, string owner)
{
this .name = name;
this .owner = owner;
}
public override String ToString()
{
return this .Name + " , belongs to " + this .Owner;
}
public virtual Object Clone()
{
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, this );
memoryStream.Position = 0 ;
return formatter.Deserialize(memoryStream);
}
}
// 大门钥匙
[Serializable]
public class GateKey : Key
{
public GateKey( string owner) : base ( " Gate Key " , owner) { }
}
// 万能 钥匙 :-)
[Serializable]
public class GeneralKey : Key
{
public GeneralKey( string name, string owner) : base (name, owner) { }
}
public class KeyManager
{
private System.Collections.Hashtable keys = new System.Collections.Hashtable();
public Key this [ string name]
{
set { keys.Add(name, value); }
get { return (Key)keys[name]; }
}
}
// 客户调用方法
public class Client
{
public static void Main( string [] args)
{
KeyManager keyManager = new KeyManager();
keyManager[ " gate " ] = new GateKey( " GF " );
keyManager[ " key2 " ] = new GeneralKey( " key2 " , " GF " );
keyManager[ " key3 " ] = new GeneralKey( " key3 " , " GF " );
keyManager[ " key4 " ] = new GeneralKey( " key4 " , " GF " );
keyManager[ " key5 " ] = new GeneralKey( " key5 " , " GF " );
Key newKey = (Key)keyManager[ " key2 " ].Clone();
newKey.Name = " Office " ;
newKey.Owner = " Me " ;
Console.WriteLine(newKey);
}
}
}
-
Prototype:抽象原型角色,定义一个原型的抽象定义,其中包含一个复制自身的接口。
-
ConcretePrototypeA/B:具体原型角色,作为原型被复制的具体对象,需实现抽象原型所定义的接口。
-
Client:客户调用端,客户使用原型对象复制出需要的对象
-
PrototypeManager:原型管理器角色,提供具体原型对象的增加、删除、浏览等管理功能。
-
当要实例化的类是在运行时刻指定时,例如,通过动态装载;
-
为了避免创建一个与产品类层次平行的工厂类层次时;
-
当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。