原型模式
The key idea is that an object can spawn other objects similar to itself.
原型模式的关键思想,是让一个对象可以产生与它自己相似的其他对象。
假设一个场景中,我们需要生成很多数量的各种种类的敌怪。
例如,先生成多个三种敌怪:幽灵、恶魔、魔法师。
它们有各自的属性,因此我们要生成对应三种敌怪的生成器类。由生成器类去生成多个敌怪。
示例代码
public class Monster
{
public string name = "";
public int attack = 0;
}
class Ghost : Monster
{
public Ghost(string n)
{
this.name = n;
this.attack = 10;
Console.WriteLine("Create a Ghost:" + this.name + " atk:" + this.attack);
}
}
public class Spawner
{
public virtual Monster spawnMonster()
{
Console.WriteLine("new Monster");
return new Monster();
}
}
public class GhostSpawner : Spawner
{
private int amount;
public override Monster spawnMonster()
{
return new Ghost("g" + amount++);
}
}
测试
GhostSpawner gs = new GhostSpawner();
Ghost? g0 = gs.spawnMonster() as Ghost;
Ghost? g1 = gs.spawnMonster() as Ghost;
DemonSpawner ds = new DemonSpawner();
Demon? d0 = ds.spawnMonster() as Demon;
Demon? d1 = ds.spawnMonster() as Demon;
这样的写法,代码结构臃肿,每一个敌怪,都要定义一个对应的生成器类。
那么,有没有办法,用一个生成器类,生成多个敌怪生成器变量呢?
答案就是原型。原型在 JavaScript 中应用广泛。
这跟工厂模式可能有点类似,就是传递一个敌怪对象作为原型,然后由生成器调用这个敌怪类的复制方法,从敌怪原型对象中克隆出一个新对象。
下面继续看示例
public class Monster
{
public string name = "";
public int attack = 0;
// 原型模式
public virtual Monster clone()
{
return new Monster();
}
}
class Ghost : Monster
{
public Ghost(string n)
{
this.name = n;
this.attack = 10;
Console.WriteLine("Create a Ghost:" + this.name + " atk:" + this.attack);
}
// 原型模式
public override Monster clone()
{
Console.WriteLine("Clone Ghost" + this.name + " atk:" + this.attack);
return new Ghost(this.name);
}
}
// 原型模式
public class SpawnerPrototype
{
private Monster prototype;
public SpawnerPrototype(Monster prototype)
{
this.prototype = prototype;
}
public Monster SpawnMonster()
{
return prototype.clone();
}
}
测试
// 创建正常的敌怪 它将作为一个原型对象
Ghost gp = new Ghost("100");
// 传入正常的敌怪原型,获得正常的敌怪生成器;如果传入特殊的敌怪原型,即可获得特殊的敌怪生成器
SpawnerPrototype gsp = new SpawnerPrototype(gp);
Ghost? gp2 = gsp.SpawnMonster() as Ghost;
gp.attack -= 5;
Console.WriteLine(gp.attack);
Console.WriteLine(gp2?.attack);
还可以使用泛型继续优化
// 泛型
public class SpawnerPrototype2<T> where T : Monster
{
private T prototype;
public SpawnerPrototype2(T p)
{
this.prototype = p;
}
public Monster SpawnMonster()
{
return prototype.clone();
}
}
测试
Demon dp = new Demon("99");
SpawnerPrototype2<Demon> dsp = new SpawnerPrototype2<Demon>(dp);
Demon? dp2 = dsp.SpawnMonster() as Demon;
另外,原型也常常用在游戏数据的建模中。