初级知识六——C#事件通知系统实现(观察者模式运用)
观察者模式,绝对是游戏中十分重要的一种模式,运用这种模式,可以让游戏模块间的通信变得简单,耦合度也会大大降低,下面讲解如何利用C#实现事件通知系统。
补充,首先说下这个系统的实现原理,不然一头扎进去就难受了,这个系统的关键就在于两个类,EventCenter 和Handler,她们关系如下:
首先定义两个接口,IEventCenter 和IEventHandlerManager,代码如下:
public interface IEventCenter : IDestroy
{
bool AddEventListener(Enum EventType, EventHandler handler); bool RemoveEventListener(Enum EventType, EventHandler handler); //触发事件
void TriggerEvent(IEvent e); //广播事件
void BroadCastEvent(); }
public delegate void EventHandler(IEvent evt);//顺带定义了下事件委托。 public interface IEventHandlerManger : IEvent,IDestroy
{
bool AddHandler(EventHandler eventHandler); bool RemoveHandler(EventHandler eventHandler); void BroadCastEvent(IEvent evt); void Clear();
}
定义完两个接口后,就分别开始实现两个接口,两个接口的实现分别为EventCenter 和EventHandlerManager,代码如下 1 public class EventCenter : MonoSingleton<EventCenter>, IEventCenter
{
private Dictionary<Enum, IEventHandlerManger> DictHandler = new Dictionary<Enum, IEventHandlerManger>(); private SafeQuene<IEvent> eventQuene = new SafeQuene<IEvent>(); public bool AddEventListener(Enum EventType, EventHandler handler)
{
bool isSuccessed;
//如果不包含EventType,就将其加入到字典中,同时新建一个EventHandlerManager()
if (!DictHandler.ContainsKey(EventType))
{
DictHandler[EventType] = new EventHandlerManager();
}
//然后将handler加入到新创建的EventHandlerManager中去。
isSuccessed = DictHandler[EventType].AddHandler(handler); return isSuccessed;
} public bool RemoveEventListener(Enum EventType, EventHandler handler)
{
if (DictHandler.ContainsKey(EventType))
{
DictHandler.Remove(EventType);
return true;
}
else
{
return false;
}
} public void TriggerEvent(IEvent e)
{
this.eventQuene.EnQuene(e);
} #region 广播事件相关 public void Update()
{
BroadCastEvent();
}
public void BroadCastEvent()
{
if (eventQuene.Count<)
{
return;
} IEvent e = eventQuene.DeQuene(); BroadCastEvent(e);
} public void BroadCastEvent(IEvent e)
{
if (e == null)
{
return;
} Enum type = e.EventType; if (!DictHandler.ContainsKey(type))
{
e.DestroySelf();
} DictHandler[type].BroadCastEvent(e);
e.DestroySelf(); } #endregion #region 清除数据相关 public void DestroySelf()
{
ClearEvenQueneAndDictHandler();
} public void OnDestroy()
{
ClearEvenQueneAndDictHandler();
} public void ClearEventQuene()
{
eventQuene.Clear();
} public void ClearEvenQueneAndDictHandler()
{
DictHandler.Clear();
ClearEventQuene();
} #endregion
}
public class EventHandlerManager : IEventHandlerManger
{
private Enum _EventType; private List<EventHandler> handler = new List<EventHandler>(); public Enum EventType
{
get
{
return _EventType;
}
} public bool AddHandler(EventHandler eventHandler)
{
if (handler.Contains(eventHandler))
{
return false;
} handler.Add(eventHandler);
return true;
} public bool RemoveHandler(EventHandler eventHandler)
{
if (!handler.Contains(eventHandler))
{
return false;
} handler.Remove(eventHandler);
return true;
} public void BroadCastEvent(IEvent evt)
{
List<EventHandler> list = new List<EventHandler>();
list.AddRange(handler); foreach (EventHandler item in list)
{
item(evt);
}
} public void Clear()
{
handler.Clear();
} public void DestroySelf()
{
if (handler !=null)
{
Clear();
handler = null;
}
} }
ok,补充说明一下,IEvent接口很简单,里面定义了一个Enum EventType的Get方法,IDestroy接口则定义了一个DestroySelf()的方法。safeQuene<T>是一个线程安全的Quene<T>,其余和Quene<T>一样。
运用这套事件广播系统也十分简单,首先,在需要有事件通知的地方预定一个enum类型,比如:
public enum FBIEvent
{
TheyHaveGuns = ,
TheyUseBoom =,
TheyAreCute =,
}
然后需要定义这三个枚举类型对应的操作函数,例如:
public class FBI
{
void HavaGun(IEvent e)
{
Debug.Log("yellow gun!");
} void UseBoom(IEvent e)
{
Debug.Log("yellow gun!");
} void TheyCute(IEvent e)
{
Debug.Log("Impossible");
}
}
最后,只需要调用EventCenter的AddEventListener()方法,将其注册进入EventCenter的DicrtHandler 字典中,就大功告成了。
触发流程:
1 其他方法,触发EventCenter的TriggerEvent(IEvent e)方法。
2 EventCenter 的eventQuene会增加一个实现了IEvent接口的类。
3 在Update()中不停执行的BroadCastEvent()函数,会从eventQuene中取出类,然后执行BroadCastEvent(IEvent e)方法。
4 根据传入的EventType类型,将从DirctHandler中取出对应的IEventHandlerManager对象,然后执行其BroadCastEvent(EventHandler hanlder)方法,
这里根据多态,实际上执行的是EventHandleManager类的BroadCastEvent(EventHandler hanlder)方法。
5 因为EventHandleManager的BroadCastEvent(EventHandler hanlder)类其实就是将该类中的List Handler中的委托全部取出来,然后执行,又因为其实
这里的每个委托在我们注册的时候,就绑定了相应的处理方法,因此,此刻执行的委托,其实就是执行的我们绑定的具体的方法。
初级知识六——C#事件通知系统实现(观察者模式运用)的更多相关文章
- Caddy源码阅读(二)启动流程与 Event 事件通知
Caddy源码阅读(二)启动流程与 Event 事件通知 Preface Caddy 是 Go 语言构建的轻量配置化服务器.https://github.com/caddyserver/caddy C ...
- SQL Server 事件通知(Event notifications)
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 基础知识(Rudimentary Knowledge) 事件通知监控DDL(NotifyQue ...
- PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)
源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...
- 很幽默的讲解六种Socket IO模型 Delphi版本(自己Select查看,WM_SOCKET消息通知,WSAEventSelect自动收取,Overlapped I/O 事件通知模型,Overlapped I/O 完成例程模型,IOCP模型机器人)
很幽默的讲解六种Socket IO模型(转)本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一:select模型 二:WSAAsyncSel ...
- ABP文档 - 通知系统
文档目录 本节内容: 简介 发送模式 通知类型 通知数据 通知重要性 关于通知持久化 订阅通知 发布通知 用户通知管理器 实时通知 客户端 通知存储 通知定义 简介 通知用来告知用户系统里特定的事件发 ...
- ABP理论学习之通知系统
返回总目录 本篇目录 介绍 订阅通知 发布通知 用户通知管理者 实时通知 通知存储 通知定义 介绍 通知(Notification)用于告知用户系统中的特定事件.ABP提供了基于实时通知基础设施的发布 ...
- Linux内核基础--事件通知链(notifier chain)
转载: http://blog.csdn.net/wuhzossibility/article/details/8079025 http://blog.chinaunix.net/uid-277176 ...
- 重叠I/O之事件通知
在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于select模型.异步选择和事件选择三种.重叠模型的基本设计原理便是让应用程序使 用一个重叠的数据 ...
- iOS 原生模块 给 Javascript(ReactNative) 发送事件 (通知监听)
官方中文文档是这样描述的: 就给我们这几句话 就打发我们了. 按照上面的写法,根本不知道 - (void)calendarEventReminderReceived:(NSNotificatio ...
随机推荐
- 【BZOJ2588】Count on a tree 题解(主席树+LCA)
前言:其实就是主席树板子啦……只不过变成了树上的查询 -------------------------- 题目链接 题目大意:求树上$u$到$v$路径第$k$大数. 查询静态区间第$k$大肯定是用主 ...
- 用 Python 可以实现侧脸转正脸?我也要试一下!
作者 | 李秋键 责编 | Carol 封图 | CSDN 下载自视觉中国 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例 ...
- Spring IOC 启动过程
1. 引言 本篇博文主要介绍 IOC 容器的启动过程,启动过程分为两个步骤,第一个阶段是容器的启动阶段,第二个阶段是 Bean 实例化阶段,这两个阶段各自需要执行的步骤如下图,接下来会一一介绍. 需要 ...
- Linux Docker部署
Docker 安装 卸载旧版docker yum remove docker \ docker-client \ docker-client-latest \ docker-common \ dock ...
- LeetCode.516 最长回文子序列 详解
题目详情 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 示例 1: 输入: "bbbab" 输出: 4 一个可能的最长回文子序列为 "bb ...
- flask-migrate 处理sqlite数据库报错Constraint must have a name 的解决方案
环境:flask+python+sqlite,我想给某个表里某个字段加unique属性 执行 python manage.py db migrate 没报错,执行 python manage.py d ...
- 防止多次引入js文件导致的重复注册点击事件
前端代码中的js文件如果是动态引入的或者是某个事件操作进行注册的,那么重复的引入js文件或者多次触发注册事件会导致事件多次进行注册,造成不必要的麻烦,所以需要在每次注册之前将先前的事件进行取消,下面以 ...
- Oracle从回收站找回误删的数据
Step1 先根据删除时间查看删除了那些表 select * from recyclebin where type = 'TABLE' and createtime like '${删除时间}%' o ...
- Promise.then返回的是什么?
console.log((function cook(){ console.log('开始做饭.'); var p = new Promise(function(resolve, reject){ / ...
- windows10永久激活工具 新版win10激活工具(绝对有效的永久激活工具)
来看这篇文章的,都用过KMS了吧?对!KMS是批量激活的,激活时间是一年,如果给女神激活,此法首选呀!!!但是帮基友激活,过了一年又来找自己,作为程序员的你,脸上是不是有点挂不住然后又不想花钱去买某宝 ...