思考并回答以下问题:
- 这3个模式各是什么意思?
本章涵盖:
- 迭代器模式
- 原型模式
- 解释器模式
迭代器模式
迭代器模式由于经常使用,因此被现代程序设计语言纳为标准语句或收录到标准函数库当中。
关于迭代器模式(Iterator),GoF的定义是:1
在不知道集合内部细节的情况下,提供一个按序方法存取一个对象集合体的每一个单元。
在使用C#的开发过程中,经常使用“泛型容器”来作为存储对象的地点。而通常想要按序存取这些泛型容器时,都会使用C#中的foreach语句。而foreach语句就是一个能顺序访问一个集合体(泛型容器)的方法。对开发者而言,不管容器是List、Dictionary还是数组(Array),一经使用foreach语句时,程序设计语言保证会让容器内的每一个成员都被存取到,也因为foreach语句(迭代器模式Iterator)非常好用,在很多现代化的程序设计语言中都提供了类似的语句。所以迭代器模式可以算是“内化”到程序设计语言的层次了。
在《P级阵地》中,到处都充斥着迭代器模式的foreach语句,举例如下:
Listing1 管理产生出来的角色(CharacterSystem.cs)
1 | public class CharacterSystem : IGameSystem |
原型模式
原型模式和复制有关,一些面向对象的程序设计语言也都将之纳为对象的方法或收录到标准函数库当中。多数的图形化开发环境也都利用原型模式的概念提供了对象的复制功能,包含Unity3D的开发环境。
关于原型模式(Prototype),GoF的定义是:1
使用原型对象来产生指定类的对象,所以产生对象时,是使用复制原型对象来完成。
在Unity3D的开发环境中,开发者可以在编辑模式下组装要放入场景中的游戏对象(GameObject),这些游戏对象可以包含复杂的组件,如模型(Mesh)、材质(Material)、程序脚本等。游戏对象组装好了之后,就可以将其存储为Prefab类型的Unity Asset资源,存放在资源目录(Resource)目录下。
在讲解加载速度的优化-代理模式时,我们就曾使用过原型模式,也就是当游戏运行时,系统可以根据需要将资源加载并经过“实例化(GameObject.Instance)”的操作之后放入场景中:
Listing2 从项目的Resource中,将Unity Asset实例化成GameObject的工厂类(ResourceAssetFactory.cs)
1 | public class ResourceAssetFactory : IAssetFactory |
程序代码中使用的实例化方法(GameObject.Instance),就是一种原型模式的应用。它将原本存储在资源目录下的Unity Asset资源“复制了一份”放入场景中,而放入场景的复制体会与原本在编辑模式下所组装的游戏对象相同。
这也是原型模式,想要表达的解决方案:将一个复杂对象的组合方式先行设置好,后续使用时就不必再经过相同的组装流程,只需要从做好的“原型”完整地复制出来就可以了,如图1所示。
图1 原型模式的示意图
在程序设计语言的层次上,大多数的程序设计语言也提供了相关的方法或函数来实现,例如,C++的复制构造函数(Copy Constructor),而C#中也提供能复制对象内容的接口。但在实现上,还是要先理解“浅层复制”与“深层复制”之间的差异,否则很容易会发生内存遗失、程序宕机等间题,一般不建议入门设计师去实现这部分。
解释器模式
关于解释器模式(Interpreter),GoF的定义是:1
定义一个程序设计语言所需要的语句,并提供解释来解析(执行)该语言。
传统上,执行程序代码通常通过两种方式:第一种采用的是编译程序;第二种采用的是解释器。前者会将源代码经过“编译程序(Compiler)”转化为目标码或中间码,然后汇编翻译为机器码,最终执行的是机器码。编译的过程只需一次,之后在执行时就不必重新编译了(除非修改了源代码)。后者则是使用一个解释器直接读入源代码,然后执行其语句。
由于两者各有优缺点,因此后来有些程序设计语言采用的方式是混合的,例如,Java会先经过编译程序把源代码编译为Byte Code,再通过JVM(解释器)来执行Byte Code。
最常见的使用解释器的程序设计语言,包含流行于网页设计领域中的脚本语言,如JavaScript、PHP、Ruby等,或者是Microsoft Office中的VBA,这些程序代码经过一般文本编辑器编写完成后放入指定的位置,就可以由应用程序中的解释器直接执行,过程中应用程序本身完全不需要做任何的变动。这些应用程序可以是:执行JavaScript的网页浏览器、放在WebServer中的PHP、Ruby的Plugin,或者是Excel、Word应用软件。而游戏开发上也有使用这类的例子,如因《魔兽世界》而名声大躁的脚本语言Lua。
在使用Unity3D引擎设计游戏时,可以选择C#或JavaScript来开发,但严格上来说,编写好的脚本程序,在执行之前都还是会被UnityEngine编译过,所以不算是解释器模式。但如果与十几年开发游戏时的工具来比较,现代使用C#来开发游戏,就会符合解释器模式的定义因为开发过程中,我们不必去重新“编译”UnityEngine,就可以得到想要的游戏功能。