Prototype原形(创建型模式)
一、动机(Motivation)问题域
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。
如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求改变而改变?
二、意图(Intent) 解决方案
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
三、结构(Structure)UML
public class Game
{
public static void Run()
{
NormalActor na1 = new NormalActor();
NormalActor na2 = new NormalActor();
NormalActor na3 = new NormalActor();
NormalActor na4 = new NormalActor();
NormalActor na5 = new NormalActor();
FlyActor fa1 = new FlyActor();
FlyActor fa2 = new FlyActor();
}
}
//步兵
public class NormalActor
{
}
//飞行兵
public class FlyActor
{
}
//重构1
public abstract AbstractNormalActor
{
}
public abstract AbstractFlyActor
{
}
public class Game
{
public static void Run()
{
AbstractNormalActor na1 = new NormalActor();
AbstractNormalActor na2 = new NormalActor();
AbstractNormalActor na3 = new NormalActor();
AbstractNormalActor na4 = new NormalActor();
AbstractNormalActor na5 = new NormalActor();
AbstractFlyActor fa1 = new FlyActor();
AbstractFlyActor fa2 = new FlyActor();
}
}
//重构2
public class Game
{
public static void Run(AbstractNormalActor na,AbstractFlyActor fa)
{
AbstractNormalActor na1 = na.clone();
AbstractNormalActor na2 = na.clone();
AbstractNormalActor na3 = na.clone();
AbstractNormalActor na4 = na.clone();
AbstractNormalActor na5 = na.clone();
AbstractFlyActor fa1 = fa.clone();
AbstractFlyActor fa2 = fa.clone();
}
}
public abstract AbstractNormalActor
{
public abstract AbstractNormalActor clone();
}
public abstract AbstractFlyActor
{
public abstract AbstractFlyActor clone();
}
//步兵
public class NormalActor
{
public override AbstractNortalActor clone()
{
return (AbstractNortalActor)this.MemberwiseClone();
}
}
//飞行兵
public class FlyActor
{
public override AbstractFlyActor clone()
{
return (AbstractFlyActor)this.MemberwiseClone();
}
}
现在Game仅仅依赖于抽象类而不依赖于具体实现类了
class App
{
void main()
{
AbstractNormalActor ana = new NormalActor();
AbstractFlyActor afa = new FlyActor();
Game.Run(ana,afa);
}
}注:MemberwiseClone()方法是.net framework默认实现,是浅拷贝。对于值类型没有问题,但对于引用类型就会出现两个对象共用一个引用值的问题了,因为它们是克隆了引用类型的地址。所以引用类型的值相同。
解决这个问题之一是实现深度拷贝,如new一个对象,把当前对象的字段值一个一个赋给新的new对象。或者通过序列化的方式来做,这是一个取巧的过程。
我们假设上面的AbstractNormalActor和AbstractFlyActor不可以进行抽象了,是不同的对象。
五、Prototype模式的要点
Prototype模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些“易变类”拥有“稳定的接口”。
Prototype模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法来做,它使得我们可以非灵活地动态创建“拥有某些稳定接口”的新对象------所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone。
Prototype模式中的Clone方法可以利用.net中的Object类的MemberwiseClone()方法或者序列化来实现深拷贝。
六、创建型模式的总结
1.Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的都是New所带来的耦合关系。
2.Factory Method,Abstract Factory,Builder都需要一个额外的工厂类来负责实例化易变对象,而Prototype则是通过原型(一个特殊的工厂类)来克隆易变对象。
3.如果遇到“易变类”,起初的设计通过从Factory Method开始,当遇到更多的复杂变化时,再考虑重构为其它三种工厂模式(Abstract Factory,Builder,Prototype)。
有关更多的Factory Method,Abstract Factory,Builder之间的区别请看Builder模式一讲,原则上来讲Abstract Factory,Prototype可以相互替换,但如果用Prototype替换Abstract Factory,那么需要创建的对象应该是很容易克隆才行,最好是能用MemberwiseClone()方法,否则显示太复杂,不划算,但理论上是可行的。


浙公网安备 33010602011771号