模拟EventCenter,flash自带的事件机制的一个解耦框架,callback回调方式用于模块之间的通信
之前写了一个简化版的puremvc,mvc框架,
后来参考一个ARPG项目的架构,目前用于解耦的我所了解的两种方式都罗列下:
1.EventCenter模式:
package com.cw.war.module.guide { import flash.events.EventDispatcher; /** * 用来解耦新手指引和各个模块 * @author elvisjiang * @data 2012-9-25 */ public class GuideEventCenter { private static var instance:GuideEventCenter; public static function getInstance () : GuideEventCenter { if (instance == null) { instance = new GuideEventCenter (); } return instance; } public static function get I():GuideEventCenter { if (instance == null) { instance = new GuideEventCenter (); } return instance; } public function GuideEventCenter() { ed = new EventDispatcher(); if(instance != null) throw new Error ( "Singleton Error" ); } private var ed:EventDispatcher; private var _listener:Array; public function dispatchEvent(type:String,data:Object = null):void { ed.dispatchEvent(new GuideEvent(type,data)); } public function addEventListener(type:String,fun:Function):void { if(!_listener) { _listener = []; } _listener.push({type:type,listener:fun}); ed.addEventListener(type,fun); } public function removeEventListener(type:String,fun:Function):void { ed.removeEventListener(type,fun); } public function destroy():void { //移除监听 while(_listener.length > 0) { var item:Object = _listener.shift(); removeEventListener(item.type,item.listener); } _listener.length = 0; _listener = null; ed = null; instance = null; } } }
上述的核心就是一个eventDispatcher用于转发,
比方说模块1 : proxy里面可以 这样写:
EventCenter.addEventListener("背包数据回包",_fun1);
服务器背包数据回包之后可以 EventCenter.dispatchEvent();
这有个缺点,整个游戏会监听很多事件,上个项目至少监听了500个,这个ed太任重道远了,
2.下面讲另一种解耦方式,函数回调的方式:
package { import flash.utils.Dictionary; import net.libra.core.Notification; import net.libra.core.interfaces.IController; import net.libra.core.interfaces.INotifier; import net.libra.log.Log; import net.libra.utils.HashMap; import net.libra.utils.StringUtils; /** * 事件转发器 * @author elvisjiang * @data 2012-6-11 */ public class CallPool { private static var _instance:CallPool; public static function getInstance () : CallPool { if (_instance == null) { _instance = new CallPool (new PrivateClass()); } return _instance; } public static function get I():CallPool { if (_instance == null) { _instance = new CallPool (new PrivateClass()); } return _instance; } public static function get instance():CallPool { if (_instance == null) { _instance = new CallPool (new PrivateClass()); } return _instance; } //----------------------------------------------------------------> private var _callbacks:Dictionary; public function CallPool(prv :PrivateClass) { _callbacks = new Dictionary(true); } //----------------------------------------------------------------------> /** * 注册消息回调 * 相当于addEventlistner; * @param noticationName 消息Type * @param fun 回调函数 */ public function addCallBack(notificationName:String,callback:Function):void { if(_callbacks[notificationName] == null){ _callbacks[notificationName] = []; } var index:int = findAt(notificationName,callback); if(index == -1){ _callbacks[notificationName].push(callback); } } /** * 销毁消息回调 * @param notificationName * @param callback * */ public function removeCallBack(notificationName:String,callback:Function):void { var index:int = findAt(notificationName,callback); if(index != -1){ (_callbacks[notificationName] as Array).splice(index,1); } } private function findAt(notificationName:String,callback:Function):int { var calls:Array = _callbacks[notificationName]; if(calls == null) return -1; var index:int = 0; for each(var call:Function in calls){ if(call == callback) return index; index++; } return -1; } /** * 向所有的注册的函数发消息 */ public function sendNotification(notificationName:String,body:Object = null):void { if(_callbacks[notificationName] != null) { var calls:Array = _callbacks[notificationName]; if(calls == null || calls.length <= 0) return ; var index:int = 0; for each(var call:Function in calls){ call.apply(null,[new Notification(notificationName,body)]); index++; } } } } } class PrivateClass{}
模块1入口
package { import net.libra.core.Notification; /** * * @author elvisjiang * @data 2012-11-14 */ public class Module1 { public function Module1() { CallPool.I.addCallBack("123",_callback1); CallPool.I.addCallBack("456",_callback1); CallPool.I.removeCallBack("123",_callback1); } private function _callback1(notification:Notification):void { switch(notification.getName()) { case "123": trace("Module1收到123"); break; case "456": trace("Module1收到456"); break; } } } }
模块2入口
package { import net.libra.core.Notification; /** * * @author elvisjiang * @data 2012-11-14 */ public class Module2 { public function Module2() { CallPool.I.addCallBack("123",_callback1); } private function _callback1(notification:Notification):void { trace("Module2--123接收到",notification.getBody().name); } } }
测试类:
package { import flash.display.Sprite; import net.libra.core.Notification; /** * * @author elvisjiang * @data 2012-11-14 */ public class TestCallPool extends Sprite { public function TestCallPool() { new Module1(); //new Module2(); CallPool.I.sendNotification("123",{name:"xxx123"}); CallPool.I.sendNotification("456",{name:"xxx456"}); } } }
消息体类
package net.libra.core { import flash.events.Event; /** * 事件通知 * @author elvisjiang */ public class Notification { private var name:String; private var body : Object; private var type : String; /** * 创建一个通知对象 * @param name 事件名称 * @param body 事件携带的数据参数 * @param type 事件类型 */ public function Notification(name : String, body : Object = null,type : String = "") { this.name = name; this.body = body; this.type = type; } /** * @inheritDoc */ public function getName() : String { return this.name; } /** * @inheritDoc */ public function setBody(body : Object) : void { this.body = body; } /** * @inheritDoc */ public function getBody() : Object { return this.body; } /** * @inheritDoc */ public function setType(type : String) : void { this.type = type; } /** * @inheritDoc */ public function getType() : String { return this.type; } } }
这种方式是基于函数回调的,就是一个字符串对应一个函数列表,当callPool.sendNotication的时候,函数列表会挨个执行。
两种方式各有优缺点,有的人说eventdispatcher是最高效率的,但是用内存换效率了,函数回调的方式弱化了a lot of 监听,但如果是高性能要求的可以用eventCenter的方式,有人说监听500到1000个函数根本不在话下,看个人了,如果你觉的太重了,就用下面那个,呵呵。