怎么创建免费网站,做网站失败,公司自己买服务器建设网站,团购手机网站怎么做原型的定义
用原型实例指定创建对象的种类#xff0c;并且通过拷贝这些原型创建新的对象。
举个例子
假设我现在要做一款游戏#xff0c;这个游戏里有许多不同种类的怪物#xff0c;鬼魂#xff0c;恶魔和巫师。这些怪物通过“生产者”进入这片区域#xff0c;每种敌人…原型的定义
用原型实例指定创建对象的种类并且通过拷贝这些原型创建新的对象。
举个例子
假设我现在要做一款游戏这个游戏里有许多不同种类的怪物鬼魂恶魔和巫师。这些怪物通过“生产者”进入这片区域每种敌人有不同的生产者。
假设每种怪物都有不同的类同时他们都继承怪兽这个基类那么我们的代码就会是这样
class Monster
{// 代码……
};class Ghost : public Monster {};
class Demon : public Monster {};
class Sorcerer : public Monster {};为了能够产生这些怪物我们需要不同的生产者类这些类都继承spawner这个基类那么我们就得写如下的代码
class Spawner
{
public:virtual ~Spawner() {}virtual Monster* spawnMonster() 0;
};class GhostSpawner : public Spawner
{
public:virtual Monster* spawnMonster(){return new Ghost();}
};class DemonSpawner : public Spawner
{
public:virtual Monster* spawnMonster(){return new Demon();}
};// 你知道思路了……那么这么一来我们的架构就类似于这样 每个怪物类都有生产者类得到平行的类结构 已经闻到臭味了……你的代码里有一堆特定的spawner将来要是有一个新怪物你就得多些一堆代码。 众多类众多引用众多冗余众多副本众多重复自我……
那么这个时候原型模式就可以派上用场了 我们来看看实现 原型模式提供了一个解决方案。 关键思路是一个对象可以产出与它自己相近的对象。 如果你有一个恶灵你可以制造更多恶灵。 如果你有一个恶魔你可以制造其他恶魔。 任何怪物都可以被视为原型怪物产出其他版本的自己。
我们给基类Monster增加一个Clone()的方法
class Monster
{
public:virtual ~Monster() {}virtual Monster* clone() 0;// 其他代码……
};
每个怪兽子类提供一个特定实现返回与它自己的类和状态都完全一样的新对象。就像这样
class Ghost : public Monster {
public:Ghost(int health, int speed): health_(health),speed_(speed){}virtual Monster* clone(){return new Ghost(health_, speed_);}private:int health_;int speed_;
};然后我们就不需要那么多特定的spawner了我们只需要一个spawner()如下
class Spawner
{
public:Spawner(Monster* prototype): prototype_(prototype){}Monster* spawnMonster(){return prototype_-clone();}private:Monster* prototype_;
};可以看到这个Spawner内部有一个Monster*类型的prototype这就是原型一个隐藏的怪物 它唯一的任务就是被生产者当做模板去产生更多一样的怪物 有点像一个从来不离开巢穴的蜂后。 当你要使用的时候你只需要这么做
Monster* ghostPrototype new Ghost(15, 3);
Spawner* ghostSpawner new Spawner(ghostPrototype);这个模式的灵巧之处在于它不但拷贝原型的类也拷贝它的状态。 这就意味着我们可以创建一个生产者生产快速鬼魂虚弱鬼魂慢速鬼魂而只需创建一个合适的原型鬼魂。
如果你还是觉得麻烦懒得写Clone()方法的话这里还有一种思路使用生产函数来代替生产者类我们这么写一个生产函数
Monster* spawnGhost()
{return new Ghost();
}这比构建怪兽生产者类更简洁。生产者类只需简单地存储一个函数指针
typedef Monster* (*SpawnCallback)();class Spawner
{
public:Spawner(SpawnCallback spawn): spawn_(spawn){}Monster* spawnMonster(){return spawn_();}private:SpawnCallback spawn_;
};而你调用的时候就这样写就行
Spawner* ghostSpawner new Spawner(spawnGhost);原型还可以做什么
原型模式不仅仅可以应用在代码之中我们还可以将其用在一些别的地方比如数据存储中。 再举个例子我们在游戏中经常使用Json来存储一些数据比如怪物的各种属性。 所以游戏中的哥布林也许被定义为像这样的东西
{name: goblin grunt,minHealth: 20,maxHealth: 30,resists: [cold, poison],weaknesses: [fire, light]
}接下来如果策划和你说我还要别的哥布林例如哥布林巫师哥布林弓箭手即使他们的很多属性都是一样的我们还是不得不这么写
{name: goblin wizard,minHealth: 20,maxHealth: 30,resists: [cold, poison],weaknesses: [fire, light],spells: [fire ball, lightning bolt]
}{name: goblin archer,minHealth: 20,maxHealth: 30,resists: [cold, poison],weaknesses: [fire, light],attacks: [short bow]
}太重复了我们讨厌重复太多重复的数据意味着我们要话更多的时间去维护和管理这是我们都不想看到的。 如果这是代码我们会为“哥布林”构建抽象并在三个哥布林类型中重用。 但是无能的JSON没法这么做。所以让我们把它做得更加巧妙些。 我们可以为对象添加prototype字段记录委托对象的名字。 如果在此对象内没找到一个字段那就去委托对象中查找。 这样我们可以简化我们的哥布林JSON内容
{name: goblin grunt,minHealth: 20,maxHealth: 30,resists: [cold, poison],weaknesses: [fire, light]
}{name: goblin wizard,prototype: goblin grunt,spells: [fire ball, lightning bolt]
}{name: goblin archer,prototype: goblin grunt,attacks: [short bow]
}这样不就好多了只需在游戏引擎上多花点时间你就能让设计者更加方便地添加不同的武器和怪物而增加的这些丰富度能够取悦玩家。
这一节的内容有好多关于原型模式的思想方面的介绍作者还介绍了原型模式在编程语言方面的应用我认为这些都是暂时对游戏编程帮助不大所以没有记录下来有兴趣的同学请翻阅原文。
原文链接https://gpp.tkchu.me/prototype.html