五邑隐侠,本名关健昌,10年游戏生涯,现隐居五邑。本系列文章以TypeScript为介绍语言。

本篇开始介绍游戏业务架构相关的内容。在游戏业务层,所有需要隔离的系统和模块间通信都可以通过消息分发解耦。例如网络返回通知、数据更新同步到界面等。

消息分发基于观察者模式设计。需要处理消息的地方向消息中心注册监听回调,派发消息时,调用消息中心的派发接口遍历该消息的监听队列,调用对应的回调方法。

先定义监听回调类型

/**
* 消息监听回调方法
*/
export type NotifyListener = (src: any, data: any) => void;

  

通过key-value方式保存监听队列

private static msg2listDict: Dictionary< string, Array<NotifyListenerInfo> > = new Dictionary< string, Array<NotifyListenerInfo> >();

  

接口定义

    /**
* 添加多次监听者,需要手动移除
* @param msg
* @param listener
* @param target
*/
public static addListener(msg: string, listener: NotifyListener, target?: any): void {} /**
* 添加单次监听者,事件触发后即移除
* @param msg
* @param listener
* @param target
*/
public static addOnceListener(msg: string, listener: NotifyListener, target?: any): void {} /**
* 移除指定消息指定的监听者
* @param msg
* @param listener
*/
public static removeMsgListener(msg: string, listener: NotifyListener): void {} /**
* 移除指定消息所有监听者
* @param msg
*/
public static removeMsgAllListeners(msg: string): void {} /**
* 移除指定目标对指定消息的监听
* @param msg
* @param target
*/
public static removeTargetMsgListen(msg: string, target: any): void {} /**
* 移除指定目标所有消息监听
* @param target
*/
public static removeTargetAllMsgListen(target: any): void {} /**
* 派发消息
* @param msg
* @param src
* @param data
*/
public static notify(msg: string, src: any, data: any): void {}

  

在添加移除实现中,需要注意某消息可能正在派发。

对于一个消息新添加的监听者,应该在当前队列消息派发完后再派发,因此,添加一个待添加队列

private static listener2add: Array<NotifyListenerInfo> = [];

  

在添加监听者时做以下判断

    // 该消息正在派发,放入待添加队列
if (NotifyCenter.notifyMsgs.indexOf(msg) >= 0) {
NotifyCenter.listener2add.push(info);
return;
}

  

同样在移除监听者时,可能正在派发消息,避免对队列的修改导致for循环异常,添加一个待移除队列,派发消息时,如果该监听者在移除队列则不派发。在消息派发完后再将其移出队列

private static listener2remove: Array<NotifyListenerInfo> = [];

  

在移除监听者时做以下判断

        // 该消息正在派发,放入待移除队列
if (NotifyCenter.notifyMsgs.indexOf(msg) >= 0) {
NotifyCenter.listener2remove.push(list[i]);
} else {
list.splice(i, 1);
}

  

派发消息时遍历指定消息下的队列

        // 队列不存在,不需要处理
let list = NotifyCenter.msg2listDict.get(msg);
if (!list) {
return;
} // 标记消息正在派发,多个消息可能同时在派发,同一消息可能标记多次
NotifyCenter.notifyMsgs.push(msg); // 处理消息派发
for (let i = 0, n = list.length; i < n; i++) {
NotifyCenter._dispatch(list[i], src, data, false);
}

  

派发消息时先判断是否在移除队列

// 在移除队列,不派发
if (NotifyCenter.listener2remove.indexOf(info) >= 0) {
return;
}

  

当前队列派发完后检查待添加队列

// 处理待添加队列派发
for (let i = 0, n = msg2add.length; i < n; i++) {
if (listener2add[i].msg == msg) {
NotifyCenter._dispatch(listener2add[i], src, data, true);
}
}

  

引入消息分发中心,隔离的系统、模块间通过消息监听和派发通信,避免互相引用耦合。

消息分发先说到这里,下一篇我们将介绍游戏业务层架构。

最新文章

  1. Oracle基本sql操作
  2. Swift-11-协议(Protocols)
  3. Sqlserver_insert语法
  4. Erlang虚拟机的启动
  5. docker - win7下构建swarm nodes实现跨host的容器之间的通信
  6. Docker+Gogs搭建个人Git服务
  7. Gitpage + hexo(3.0以上)搭建博客
  8. 主流PHP框架间的比较(Zend Framework,CakePHP,CodeIgniter,Symfony,ThinkPHP,FleaPHP)
  9. SSH框架组建时碰到的一些问题
  10. Python存储系统(Memcached)
  11. SQLserver2008一对多,多行数据显示在一行
  12. Too many open files问题解决
  13. virtualenvwrapper虚拟环境
  14. 机器学习之朴素贝叶斯&amp;贝叶斯网络
  15. 21.PHP实现Word/Excel/PPT转换为PDF
  16. Web服务并发I/O模型
  17. java异常中throw和throws的区别
  18. ubuntu16.04安装五笔输入法
  19. Android6.0执行时权限解析,RxPermissions的使用,自己封装一套权限框架
  20. iPhone 和 Galaxy高速拍照原理具体分析

热门文章

  1. 关于CocoaPods的ruby镜像文件问题
  2. Layer 使用
  3. jdk源码阅读笔记-Integer
  4. 《HelloGitHub》第 35 期
  5. 如何定义开发完成?(Definition of Done)
  6. 我们为什么要搞长沙.NET技术社区(二)
  7. Java虚拟机三:OutOfMemoryError异常分析
  8. 将一个html文件引入另一个html文件的div中
  9. 【IIS】解决IIS无响应假死状态,asp突然无法访问重启后可以使用是什么原因
  10. 解决 mac 10.14.4 无法 sublime text 3207 安装 Package Control,以及安装第三方包报错 `Package Control There are no packages available for installation`