为什么80%的码农都做不了架构师?>>>

我第一次听到”原型“这个词是在《设计模式》中。今天,好像每个人都在谈论这个词,但是结果并不是在谈论设计模式。我们会讲到它,但是我也会展示其他的这个词和其后的概念出现过的地方。但首先,让我们先回顾一下原始的模式。

The Prototype Design Pattern

假设我们正在做一个挑战类型的游戏。各种生物和恶人成群结队围绕着英雄,争着要吃掉他的肉体。这些令人讨厌的吃友通过“生成器”进入竞技场,每种敌人都有一种生成器。

在这个例子中,不同的怪物有不同的类-鬼,恶魔,魔法师等:

class Monster
{// Stuff...
};
class Ghost : public Monster
{};
class Demon : public Monster
{};
class Sorcerer : public Monster
{};

一个生成器构造一种怪的实例。为了支持所有的怪,我们会暴力地为每种怪定义一个生成器,形成平行的类层级关系:

实现它就像这样:

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();}
};
// You get the idea...

除非你是按代码行数领工资的,否则这显然不是一种有趣的方法。大量的类,大量的样板,大量的冗余,大量的重复,大量的重复我说的话……

原型模式提供了一种解决方法。核心思想就是,一个对象可以产生类似于自身的其他对象。如果你有一个鬼,你可以产生更多的鬼。如果你有一个恶魔,你可以产生其他恶魔。任何怪物都可以作为原型产生其他的怪。

为了实现其它,我们为基类Monster定义一个纯虚函数Clone():

class Monster
{
public:virtual ~Monster() {}virtual Monster* clone() = 0;// Other stuff...
};

每一个Monster子类提供一个实现,返回与自身属性相同的新对象。例如:

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_;
};

一旦所有Monster都支持了,我们就不需要为每种怪定义一个生成器了,我们只需定义一个即可:

class Spawner
{
public:Spawner(Monster* prototype): prototype_(prototype){}Monster* spawnMonster(){return prototype_->clone();}private:Monster* prototype_;
};

它的内部定义一个Monster,其唯一的目的是用作模板产生更多类似的Monster,就像从不离开蜂房的蜂王一样。

为了创建一个鬼生成器,我们创建一个鬼的实例用作原型,然后创建一个生成器绑定这个实例:

Monster* ghostPrototype = new Ghost(15, 3);
Spawner* ghostSpawner = new Spawner(ghostPrototype);

这个模式整洁的一点是,它不仅产生原型类型的对象,还复制了它的状态。这意味着我们可以产生快鬼,弱鬼,慢鬼只需要创建相应的原型即可。

我发现了这个模式一些优雅又惊讶的地方。我不敢想象是我自己提出来的,我更不敢想象我现在竟然还不了解它。

How well does it work?

我们不必为每个Monster定义一个生成器类,这很好。但是我们必须为每个Monster实现clone()方法。这跟定义spawner的代码差不多一样多。

当你准备写正确的clone()函数时,你会发现有几个恶劣的陷阱。它是深复制还是浅复制?换句话说,就是如果一个恶魔拿着一把干草叉,复制恶魔时要不要复制干草叉?

我们中的大多数知道过多的类层级会很难管理,这就是为什么我们使用component和type object模式的原因,使用这些模式可以对不同的实体进行分类建模不至于它们混在一起。

spawn functions

即使为每个Monster创建一个spawner,我们还是有其他的方式来实现的。相比为每个Monster定义一个spawner,我们可以定义函数,就像这样:

Monster* spawnGhost()
{return new Ghost();
}

这样就比定义一个类少点恶心。然后唯一的spawner类就可以存储一个函数指针:

typedef Monster* (*SpawnCallback)();
class Spawner
{
public:Spawner(SpawnCallback spawn): spawn_(spawn){}Monster* spawnMonster(){return spawn_();}
private:SpawnCallback spawn_;
};

为了创建一个鬼的spawner,你会这么做:

Spawner* ghostSpawner = new Spawner(spawnGhost);

Templates

现在,大多数C++的程序员都对模板比较熟悉了。我们要创建产生某种Monster类型的spawner实例,但是我们不想硬编码特定的Monster类型。自然的方法就是使它变成类型参数,这正是模板要做的:

class Spawner
{
public:virtual ~Spawner() {}virtual Monster* spawnMonster() = 0;
};
template <class T>
class SpawnerFor : public Spawner
{
public:virtual Monster* spawnMonster() { return new T(); }
};

使用起来就像这样:

Spawner* ghostSpawner = new SpawnerFor<Ghost>();

First-class Types

以上两个方案解决了需要根据类型生成一个spawner实例的问题。在c++中,并不是所有类型都是“一级”的,所以需要一些变通。如果你使用动态类型语言,像JavaScript,Python和Ruby这种类就是普通的对象可以随便传递的语言,你就解决这个问题更容易。

当你要生成一个spawner时,你只要把要产生Monster对象传进去。so easy。

所有这些选项,我承认我没有找到一个案例使用原型模式是最好的解决方法。也许你有不同的经验,但是现在我们放下这点,谈点别的:原型模式作为语言范式。

The Prototype language paradigm

许多人认为“面向对象”与“类”就是同义词。相比结构型语言C和函数式语言scheme,“面向对象”的特点就是将数据和行为紧绑在一起。

你可能认为类是实现它的唯一方式,但是一小部分人包括Dave Ungar和Randall Smith。他们创造了一种叫做Self的语言。但是作为面向对象语言,它没有类。

转载于:https://my.oschina.net/xunxun/blog/487133

《游戏程序设计模式》 1.4 - 原型模式相关推荐

  1. 设计模式之【原型模式】,深入理解深拷贝与浅拷贝

    文章目录 一.什么是原型模式 二.原型模式实现方式 1.传统方式 2.原型模式 熟悉浅拷贝和深拷贝 浅拷贝实现对象克隆 深拷贝实现对象克隆 一.什么是原型模式 原型模式: 用一个已经创建的实例作为原型 ...

  2. Java描述设计模式(05):原型模式

    一.原型模式简介 1.基础概念 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象. 2.模式结构 原型模式要求对象实现一个 ...

  3. Java设计模式5:原型模式

    原型模式 原型模式属于对象的创建模式,通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的用意. 原型模式结构 原型模式要求对象实现一个 ...

  4. 使程序运行更高效——原型模式

    1.原型模式介绍 原型模式是一个创建型的模式.原型二字表明了该模式应该有一个样板实例,用户从这个样板对象中复制出一个内部属性一致的对象,这个过程也就是我们俗称的"克隆".被复制的实 ...

  5. java设计模式之五(原型模式)

    什么是原型模式? 原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 当我们程序中有几个相似但又不 ...

  6. 设计模式学习笔记-原型模式

    一.概述 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象: 二.模式中的角色 Prototype:声明一个克隆自身的接口: ConcretePrototype:实现一个克隆自身的操作: ...

  7. 【设计模式 06】原型模式(克隆??)

    原型模式(clone?) Prototype pattern refers to creating duplicate object while keeping performance in mind ...

  8. java 设计模式 优缺点_java设计模式2:原型模式(机制\优缺点分析\使用场景)...

    1. 原型模式实现机制 原型模式在设计模式中相对比较简单,它直接通过实现 Cloneable接口,再重写 clone()方法返回想要的对象就OK 了. 一起来看下代码 : public class P ...

  9. 设计模式之九原型模式

    问题描述 在开发中你也许遇到过大篇幅的使用get或set赋值的场景,例如: public void setParam(ExamPaperVo vo){ExamPaper examPaper = new ...

最新文章

  1. [转]Java8-本地缓存
  2. tableau必知必会之拖拽功能失效是怎么回事
  3. Vue怎么将后台(springboot)中的图片显示到前端表格中
  4. 香帅的北大金融学课笔记10 -- 金融衍生品
  5. windows 下redis在后台运行(亲测)
  6. [答网友问]让GridLength支持动画
  7. 《编程题》来自某游戏公司
  8. Lesson 1:单线程 Socket Communications(一)
  9. 机器字长、存储字长、指令字长
  10. (王道408考研操作系统)第三章内存管理-第一节5:动态分区分配算法(首次适应、和邻近适应)
  11. Vue.js 第1章 Vue常用指令学习
  12. 重庆计算机一级考试在线做,全国(重庆考区)计算机一级考试教程.doc
  13. 哈哈,用FlexGrid做开发,轻松处理百万级表格数据
  14. 七日杀局域网找不到服务器,7日杀局域网的联机教程步骤图
  15. 分别实现:css动画、js动画、vue动画
  16. Redis之性能指标、监控方式
  17. Kindle 电子书分享
  18. 【Java安装】Linux(CentOS7) Java8下载安装配置
  19. VMware Workstation 12
  20. 轻松构建微服务之分库分表

热门文章

  1. 电子病历、HL7交流QQ群:14739311欢迎一起交流
  2. Exchange 2003允许部分用户发送邮件到部分外网服务器
  3. 【Scala】Scala-调用Java-集合
  4. php excel类 ,phpExcel使用方法介绍
  5. [转]创业团队的那些事儿
  6. MYSQL 集群的数据节点错误信息归档
  7. 第三天-零基础学习python
  8. Ubuntu中设置防火墙的开启与关闭
  9. Linux字体显示不同颜色
  10. Cflow使用具体解释