一个最精简的MVC系统

Posted on February 7, 2015

其实我蛮不理解MVC这种东西怎么会被写成一个框架的,它应该只是一篇项目结构的规范文档。没有具体考证,我所知道的最早引入MVC的也用的最好的应该是JAVA Web开发,Spring之类的框架。后来不知道谁开始把这套web架构推广到了游戏开发里。搜索一下MVC你会发现无数的框架出来:PureMVC,RobotLegs。。。我不知道具体到底有多少人在用这些框架,至少我所认识人和游戏项目,好像都没见过有用这些的。没有深入使用过不敢妄下评论,但是简单看了一些内容,感觉这些框架里提供的各种附加功能,似乎都跟MVC没有什么关系啊。。。可能也是我了解不够深入,欢迎资深的使用者来探讨一下。:D

我所理解的MVC系统,主要是为了解决多人项目协作用的。如何让多人协作开发互不影响呢?那自然是要按功能分模块。具体要实现的目标是:关闭了其中几个非必需模块,其他模块也能正常运行,彼此之间没有直接的依赖和引用关系。从而让多个程序员能达到互不干扰地独立开发。一旦把模块解耦开,那就必须再提供一个模块间的通讯机制。要有一个Context作为总线,所有模块都持有它,并通过它来发送监听各种命令。这件事做到这里就完成了,不需要更多功能。下面分享一下我们项目中使用过的最精简的MVC系统,上截图:

MVC2

简单介绍一下包结构,code包下有三个包,分别是app,common,和module。

(一)app:应用程序初始化模块。

1.mvc核心类:

Actor:命令总线通讯基类。项目里需要模块间通信的类,比如Model和Controller都应该是它的子类。

Command:命令基类。扩展自Event,使用原生的事件流机制来实现命令通信。这个类起到区分模块间命令和视图事件的作用。所有自定义命令都应该是它的子类。

Context:命令总线上下文。它是命令的实际监听和抛出对象,并包含舞台引用,公共数据和公共视图三个属性。它已经注入到Actor类里。因此所有Actor子类都可以访问到那三个属性。

Controller:控制器基类。所有控制器都应该是它的子类。扩展自Actor,仅添加了个start()方法,必须确保子类控制器的逻辑代码都在start()里启动,而不是构造函数。

2.项目初始化和全局配置类。

AppInit:程序初始化启动类。负责程序的启动顺序,确保需要的资源都已经获得后再启动控制器列表的start()方法。

CommonData:公共数据类。模块间共享的数据都定义在这里面。它是一个静态数据类,里面不应该有任何逻辑代码,只起到存储共享的作用。

CommonView:公共视图类。模块间共享的视图都定义在这里面。规则同上。

ControllerList:控制器列表。所有功能模块的控制器都在这里实例化。并在start()方法里按一定顺序启动。最后由AppInit启动它。

(二)common:公共模块。

整个项目通用的代码(被多个功能模块引用,不属于任何单独的一个功能模块)放置在common包下。通常是命令类,工具类。也包含各种管理器,比如资源管理器,场景管理器等全局需要引用的代码。

(三)module:功能模块。

能够按具体功能独立解耦出来的模块放置在module包下。以模块名命名子包名。模块包下创建一个控制器,和三个子包,包名为command,view和model。一个模块只有一个控制器,但是可以有多个model,和多个view。控制器实例化并持有多个model和view。view负责刷新显示的部分,model负责存储和处理数据,剩下的全都是controller负责,包括事件监听,收发命令,可以理解为它就是个搅拌机。而command负责模块间通信,model和controller都可以收发command。最后创建的包结构大致可以参考上图。创建了sample模块后,还要记得把SampleController在app包下的ControllerList里实例化,并调用start()方法。如下:

package code.app
{
	import code.module.sample.SampleController;

	/**
	 * 控制器列表
	 * @author Dom
	 */
	public class ControllerList
	{
		/**
		 * 构造函数
		 */		
		public function ControllerList()
		{
		}

		private var sampleController:SampleController = new SampleController();
		/**
		 * 启动所有控制器
		 */		
		public function start():void
		{
			sampleController.start();
		}
	}
}

这里还需要说明一下,这只是个参考,并不用按照条条框框一层不变地去使用。可以根据实际项目的特点进行简单调整。例如在开发应用软件项目情况下,module下按功能模块分包的结构就不合理了。游戏里的功能模块可以分的比较清楚,每个模块都会有自己的数据模型,视图和控制器。而应用软件里大多数是全局互相作用的,一个功能可能只有控制器或只有数据模型。所以更合适的结构是module下直接创建四个目录:command,controller,model,view。对号入座即可。

最后,附上完整例子:MVC参考实现 使用说明:这并不是一个库,因为每个类你都可能直接修改它,直接把模板拷贝到项目里用即可。正式使用时可以删掉module下的sample目录,并对应删除app包下ControllerList里的sampleController定义。