今天我们继续来聊下Prototype原型模式。这篇应该是关于工厂设计模式的最后一篇。下次就往内部讲解结构类型的设计模式。首先我们说下Prototype原型模式的用法。Prototype原型模式主要是用来处理依赖关系的倒置。 比如抽象A类依赖了实现细节B:
拿我们上个帖子举例,比如我们的小车依赖于汽油发动机。 但是当我们的小车不使用汽油发动机,改用电动了,那这时候修改起来就比较痛苦了。所以我们采用抽象A依赖于抽象B,实现细节b依赖于抽象B。
那现在 我们的小车就依赖于抽象类发动机,然后不管电动还是汽油发动机都依赖于抽象类发动机。下面来看点代码的具体实现。 假设我们现在做一套机器人AI。那么机器人分为普通机器人,飞行机器人,水下机器人。那么我们先来制作这些机器人原型,来体现出我们的Prototype原型模式的用法。
public abstract class NormalRobot
{
public abstract NormalRobot Clone();
}
首先我们声明一个抽象类 普通机器人。 然后这个普通机器人有一个抽象的Clone方法,并返回这个抽象类。接下来再来写2个原型类。
public class NormalRobotA : NormalRobot
{
public override NormalRobot Clone()
{
Console.WriteLine("开始制作普通机器人A号");
return (NormalRobotA)this.MemberwiseClone();
}
}
public class NormalRobotB : NormalRobot
{
public override NormalRobot Clone()
{
Console.WriteLine("开始制作普通机器人B号");
return (NormalRobotB)this.MemberwiseClone();
}
}
现在我们又构建了2个AB号的普通机器人。重写了Clone方法。这里提一下
this.MemberwiseClone();
使用的是.net的一个深度复制方法,目的就是要把我们的原型,
数据内容重新克隆一次,然后返回出去。 这个深度复制这里我就不展开了,想了解详细的话就自行百度下吧。
好,那我们现在普通机器人的原型做好了,我们再来加上飞行机器人和水下机器人,然后再来说用法。
public abstract class FlyRobot
{
public abstract FlyRobot Clone();
}
public class FlyRobotA : FlyRobot
{
public override FlyRobot Clone()
{
Console.WriteLine("开始制作飞行机器人A号");
return (FlyRobotA)this.MemberwiseClone();
}
}
public class FlyRobotB : FlyRobot
{
public override FlyRobot Clone()
{
Console.WriteLine("开始制作飞行机器人B号");
return (FlyRobotB)this.MemberwiseClone();
}
}
public abstract class WaterRobot
{
public abstract WaterRobot Clone();
}
public class WaterRobotA : WaterRobot
{
public override WaterRobot Clone()
{
Console.WriteLine("开始制作水上机器人A号");
return (WaterRobotA)this.MemberwiseClone();
}
}
public class WaterRobotB : WaterRobot
{
public override WaterRobot Clone()
{
Console.WriteLine("开始制作水上机器人B号");
return (WaterRobotB)this.MemberwiseClone();
}
}
好,现在我们再来写一个构造器 目的就是调用这3种机器人类型。
public class GameSystem
{
public void Run(NormalRobot BasenormalRobot,FlyRobot BaseflyRobot, WaterRobot BasewaterRobot)
{
NormalRobot noramlActor1 = BasenormalRobot.Clone();
FlyRobot flyRobot = BaseflyRobot.Clone();
WaterRobot waterRobot = BasewaterRobot.Clone();
}
}
可以看到,构造器主要是传3个参数,分别就是机器人的抽象类。然后在类里面重新new出3个抽象类来接收这些参数。然后使用参数的.Clone方法来赋值。
好,最后我们来写这个启动代码,来调用这个构造器并且传输参数试试。
class Program
{
static void Main(string[] args)
{
GameSystem gameSystem = new GameSystem();
gameSystem.Run(new NormalRobotA(), new FlyRobotA(), new WaterRobotB());
Console.ReadKey();
}
}
可以看到,在Main函数中,我先new了一个构造器,然后分别往构造器传输 普通机器人A,飞行机器人A,水下机器人B。然后我们运行就可以看到每个类型的机器人
都响应了。
我们再来看看 Prototype原型模式的几个设计要点。
prototype设计模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有"稳定的接口"。
prototype设计模式对于"如何创建易变类的实体对象"采用"原型克隆"的方法来做,它使得我们可以非常灵活地动态创建"拥有某些稳定接口"的新对象--所需工作仅仅是注册一个新类的对象(即原型),然后在任何需要的地方不断地Clone。
prototype设计模式中的Clone方法可以利用.NET中的Object类中的MemberwiseClone()方法或者序列化来实现深度复制。
最后再来回顾下我们全部的工厂设计模式的方案。
Singleton模式解决的是实体对象个数的问题。除了Singleton之外,其他创建型模式解决的都是new所带来的耦合关系。
Factory Method,AbstractFactory,Builder都需要一个额外的工厂类来负责实例化"易变对象",而Prototype则是通过原型(一个特殊的工厂类)来克隆"易变对象"
如果遇到"易变类",起初的设计通常从Factory Method开始,当遇到更多的复杂变化时,再考虑重构为其他三种工厂模式(Abstract Factory,Builder,Prototype ).