原型(Prototype)模式:创建型模式
使用原型实例指定创建对象的种类,然后通过拷贝这些原型实例来创建新的对象。
动机
在软件系统中,经常面临着“某些结构复杂的对象”的创建工用;由于需求变化,这些对象经常
面临着剧烈变化,但是它们却拥有比较稳定一致的接口。
如何应对这种变化?如何向客户端程序隔离出这些易变对象,从而使得依赖这些易变对象的客户
端程序不随着需求改变而改变?
要点
Prototype模型同样用于隔离对象的使用者和具体类之间的紧耦合关系,它同样要求这些易变类
拥有稳定的接口。Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法
来做,它使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象--所需工作仅仅是注
册一个新类的对象(即原型),然后在任何需要的地方不断的克隆即可。
Prototype模式中的Clone方法可以利用.net中的Object类的MemberwiseClone()方法、序列化
(使用BinaryFormatter类,需在序列化的目标类上加【Seriallize】特性)或反射的方法来实
现,MemberwiseClone()方法为浅拷贝,即值类型成员的数据值直接拷贝到新对象中,两对象互
不影响,但引用类型的成员只是拷贝引用,不拷贝指向的对象,新旧对象的该类成员仍然指向相
同的对象,这样就会相互影响;序列化(BianrySeriallize,需在在类上加【Seriallize】特性
)或反射的方法则可以避免以上问题,被称为深拷贝。
代码示例:
一般实现,紧耦合,依赖具体类型,不利于扩展,违反开闭原则。
//实现ICloneable接口
class MP3Palyer:ICloneable
{
/// <summary>
/// 当前播放进度
/// </summary>
public int CurPlayProcessValue { get; set; }
/// <summary>
/// 当前歌典名称
/// </summary>
public string CurSingName { get; set; }
public string[] SingsList = new string[10];
public object Clone()
{
//使用object类的克隆方法,浅拷贝
return this.MemberwiseClone();
}
}
调用:
/// <summary>
/// 在调用者内部使用new来创建对象,紧耦合,依赖具体类型
/// </summary>
static void CreatePlayer()
{
//建立1000个播放器,使用new方式
MP3Palyer pp = new MP3Palyer();
for (int i = 0; i < 100000; i++)
{
//效率低下
//MP3Palyer pc = new MP3Palyer();
//类的实现了ICloneable接口,效率比new的方式高
MP3Palyer pc = (MP3Palyer)pp.Clone();
}
}
或
/// <summary>
/// 在调用者内部使用传入实例的来创建(Clone方法)新对象,紧耦合,依赖具体类型
/// </summary>
/// <param name="player"></param>
static void CreatePlayer(MP3Palyer player)
{
//创建1000个播放器实例
for (int i = 0; i < 100000; i++)
{
//类的实现了ICloneable接口,效率比new的方式高
MP3Palyer pc = (MP3Palyer)player.Clone();
}
}
原型模式实现,松耦合,不依赖具体类型,利于扩展,符合开闭原则。
//抽象接口
abstract class IPlayer : ICloneable
{
public abstract object Clone();
}
/// <summary>
/// 实现Player接口
/// </summary>
class MP3Palyer : IPlayer
{
/// <summary>
/// 当前播放进度
/// </summary>
public int CurPlayProcessValue { get; set; }
/// <summary>
/// 当前歌典名称
/// </summary>
public string CurSingName { get; set; }
public string[] SingsList = new string[10];
/// <summary>
/// 克隆,浅拷贝
/// </summary>
/// <returns></returns>
public object Clone()
{
//使用object类的克隆方法,浅拷贝
return this.MemberwiseClone();
}
}
/// <summary>
/// 实现Player接口
/// </summary>
class MP4Palyer : IPlayer
{
/// <summary>
/// 当前播放进度
/// </summary>
public int CurPlayProcessValue { get; set; }
/// <summary>
/// 当前歌典名称
/// </summary>
public string CurSingName { get; set; }
public string[] SingsList = new string[10];
/// <summary>
/// 克隆,浅拷贝
/// </summary>
/// <returns></returns>
public object Clone()
{
//使用object类的克隆方法,浅拷贝
return this.MemberwiseClone();
}
}
调用:
/// <summary>
/// 在调用者内部使用传入实例的来创建(Clone方法)新对象,松耦合,依赖接口
/// </summary>
/// <param name="player"></param>
static void CreatePlayer(IPlayer player)
{
for (int i = 0; i < 100000; i++)
{
IPlayer pc = (IPlayer)player.Clone();
}
}
static void Main()
{
CreatePlayer(new MP3Palyer());
CreatePlayer(new MP4Palyer());
}
创建型设计模式总结
单例(Singleton)模式解决的是实体对象个数的问题,除了单例模式外,其它创建型模式解决的
都是new对象所带的耦合关系。
工厂方法(Factory Method)、抽象工厂(Abstract Factory)、生成器(Builder)模式都需要一
个额外的工厂类来负责实例化“易变对象”,而原型(Prototype)模式则是通过原型(一个特殊的
工厂类)来克隆“易变对象”。
如果遇到“易变类”,起初的设计通常从工厂方法模式开始,当遇到更多的复杂变化时再考虑重
构为其他三种模式(抽象工厂、生成器、原型)。