设计模式之Prototype的学习笔记
Prototype (原型模式)
抽象不应该依赖于实现细节,实现细节应该依赖于抽象。
------抽象A依赖于抽象B,实现细节b依赖于抽象B。
动机(Motivation)
动机(Motivation)
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化
这些对象经常变量着剧烈的变化,但是它们却拥有比较稳定一致的接口。
这些对象经常变量着剧烈的变化,但是它们却拥有比较稳定一致的接口。
如何应对这种变化?如何向“客户程序(使用这些对象的程序)”隔离出
“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着改变而
改变?
意图(Intent)
“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着改变而
改变?
意图(Intent)
使用原型实例指定创建对象的种类,然后通过拷贝这些原型来创建新的对象。
先看一个例子:
public class GameSystem
{
public static void Run()
{
{
public static void Run()
{
//需要5个小兵
NormalActor noramlActor1=new NormalActor();
NormalActor noramlActor2=new NormalActor();
NormalActor noramlActor3=new NormalActor();
NormalActor noramlActor4=new NormalActor();
NormalActor noramlActor5=new NormalActor();
NormalActor noramlActor1=new NormalActor();
NormalActor noramlActor2=new NormalActor();
NormalActor noramlActor3=new NormalActor();
NormalActor noramlActor4=new NormalActor();
NormalActor noramlActor5=new NormalActor();
//需要两个飞人
FlyActor flyActor1=new FlyActor();
FlyActor flyActor2=new FlyActor();
FlyActor flyActor1=new FlyActor();
FlyActor flyActor2=new FlyActor();
//需要潜水员
WaterActor waterActor1=new WaterActor ();
WaterActor waterActor2=new WaterActor ();
}
}
WaterActor waterActor1=new WaterActor ();
WaterActor waterActor2=new WaterActor ();
}
}
上边的代码依赖关系很强,如果这个场景中就需要这么些类型的人
整个场景都保持不变,ok上面的代码可以,没问题。
但是需求往往需要变化的,比如我要6个小兵,或者再需要一类人。
上边这种强依赖关系就不能满足要求了
上边这种强依赖关系就不能满足要求了
那又该如何来更改这个代码?
再看一个例子:
//抽象接口
public abstract class NormalActor
{
public abstract NormalActor Clone();
}
public abstract class FlyActor
{
public abstract FlyActor Clone();
}
{
public abstract FlyActor Clone();
}
public abstract class WaterActor
{
public abstract WaterActor Clone();
}
//具体实现
public class NormalActorA:NormalActor
{
public override NormalActor Clone()
{
return (NormalActor)this.MemberwiseClone();
}
}
public class NormalActorA:NormalActor
{
public override NormalActor Clone()
{
return (NormalActor)this.MemberwiseClone();
}
}
public class FlyActorA:FlyActor
{
public override FlyActor Clone()
{
return (FlyActor)this.MemberwiseClone();
}
}
public abstract class WaterActorA:WaterActor
{
public override WaterActor.Clone()
{
return (WaterActor)this.MemberwiseClone();
}
}
{
public override FlyActor Clone()
{
return (FlyActor)this.MemberwiseClone();
}
}
public abstract class WaterActorA:WaterActor
{
public override WaterActor.Clone()
{
return (WaterActor)this.MemberwiseClone();
}
}
public class GameSystem
{
public static void Run(NormalActor normalActor,
FlyActor flyactor,
WaterActor waterActor
)//如果把参数定义成属性也可以的不影响设计模式的实现。
{
//需要5个小兵
NormalActor noramlActor1=normalActor.Clone();//克隆
NormalActor noramlActor2=normalActor.Clone();
NormalActor noramlActor3=normalActor.Clone();
NormalActor noramlActor4=normalActor.Clone();
NormalActor noramlActor5=normalActor.Clone();
NormalActor noramlActor1=normalActor.Clone();//克隆
NormalActor noramlActor2=normalActor.Clone();
NormalActor noramlActor3=normalActor.Clone();
NormalActor noramlActor4=normalActor.Clone();
NormalActor noramlActor5=normalActor.Clone();
//需要两个飞人
FlyActor flyActor1=flyactor.Clone();
FlyActor flyActor2=flyactor.Clone();
FlyActor flyActor1=flyactor.Clone();
FlyActor flyActor2=flyactor.Clone();
//需要潜水员
WaterActor waterActor1=waterActor.Clone();
WaterActor waterActor2=waterActor.Clone();
}
}
WaterActor waterActor1=waterActor.Clone();
WaterActor waterActor2=waterActor.Clone();
}
}
//客户程序
class App
{
public static void Main()
{
GameSystem gamesystem=new GameSystem();
{
public static void Main()
{
GameSystem gamesystem=new GameSystem();
gamesystem.Run(new NormalActorA(),
new FlyActorA(),
new WaterActorA())
new FlyActorA(),
new WaterActorA())
}
}
}
注意上边的代码中 MemberwiseClone 它是一个类的前拷贝。如类中的属性是
值类型比如说int a ,bety b, string s;这些属性定义的变量MemberwiseClone
克隆没有问题,如果类里面有一个数组 int [] a;MemberwiseClone 克隆的就是它
的地址了。这样克隆就会存在问题。
值类型比如说int a ,bety b, string s;这些属性定义的变量MemberwiseClone
克隆没有问题,如果类里面有一个数组 int [] a;MemberwiseClone 克隆的就是它
的地址了。这样克隆就会存在问题。
如何解决这个问题?
最差劲的做法就是先new 一个东西 然后一步步再把它们给复制过来。
还有一种做法其实是蛮取巧的就是我们讲的那个用序列化的方式,其实序列化
就要求我们这样在这个类上声明这样一个标记,声明这样一个标记之后,可以
先将这样一个类序列化到这个内存流上然后再进行一个反序列化,那反序列化
得到的对象或原来的对象一定就是一个深拷贝关系
Prototype 模式的几个要点
Prototype 模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合
关系,它同样要求这些易变类拥有稳定的接口。
prototype 模式对于“如何创建易变类的实体对象”采用“原型克隆”的方法
来做,他使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象
---------所需工作仅仅是注册一个新类的对象(即原型),然后在任何
需要的地方不断地Clone。
来做,他使得我们可以非常灵活地动态创建“拥有某些稳定接口”的新对象
---------所需工作仅仅是注册一个新类的对象(即原型),然后在任何
需要的地方不断地Clone。
prototype模式中的Clone 方法可以利用.net中的Object类的MemberwiseClone()
方法或者序列化来实现深拷贝。
方法或者序列化来实现深拷贝。
有关创建型模式的讨论
Singletion 模式解决的是实体对象个数的问题。出了Singletion
之外,其他创建型模式解决的都是new 的耦合关系。
之外,其他创建型模式解决的都是new 的耦合关系。
Factory Method,Abstract Factory,Builder都需要一个额外的工厂类来
负责实例化“易变对象”,而Prototype则是通过一个原型(一个特殊的工厂类)
来克隆易变对象。
如果遇到“易变类”起初的设计通常从Factory Method开始,当遇到更多的复杂变化
时,再考虑重构为其他三种工厂模式(Abstract Factory,Builder,
Prototype)。
时,再考虑重构为其他三种工厂模式(Abstract Factory,Builder,
Prototype)。