观察者模式,绝对是游戏中十分重要的一种模式,运用这种模式,可以让游戏模块间的通信变得简单,耦合度也会大大降低,下面讲解如何利用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#事件通知系统实现(观察者模式运用)的更多相关文章

  1. Caddy源码阅读(二)启动流程与 Event 事件通知

    Caddy源码阅读(二)启动流程与 Event 事件通知 Preface Caddy 是 Go 语言构建的轻量配置化服务器.https://github.com/caddyserver/caddy C ...

  2. SQL Server 事件通知(Event notifications)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 基础知识(Rudimentary Knowledge) 事件通知监控DDL(NotifyQue ...

  3. PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)

    源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...

  4. 很幽默的讲解六种Socket IO模型 Delphi版本(自己Select查看,WM_SOCKET消息通知,WSAEventSelect自动收取,Overlapped I/O 事件通知模型,Overlapped I/O 完成例程模型,IOCP模型机器人)

    很幽默的讲解六种Socket IO模型(转)本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一:select模型 二:WSAAsyncSel ...

  5. ABP文档 - 通知系统

    文档目录 本节内容: 简介 发送模式 通知类型 通知数据 通知重要性 关于通知持久化 订阅通知 发布通知 用户通知管理器 实时通知 客户端 通知存储 通知定义 简介 通知用来告知用户系统里特定的事件发 ...

  6. ABP理论学习之通知系统

    返回总目录 本篇目录 介绍 订阅通知 发布通知 用户通知管理者 实时通知 通知存储 通知定义 介绍 通知(Notification)用于告知用户系统中的特定事件.ABP提供了基于实时通知基础设施的发布 ...

  7. Linux内核基础--事件通知链(notifier chain)

    转载: http://blog.csdn.net/wuhzossibility/article/details/8079025 http://blog.chinaunix.net/uid-277176 ...

  8. 重叠I/O之事件通知

      在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于select模型.异步选择和事件选择三种.重叠模型的基本设计原理便是让应用程序使 用一个重叠的数据 ...

  9. iOS 原生模块 给 Javascript(ReactNative) 发送事件 (通知监听)

    官方中文文档是这样描述的:   就给我们这几句话 就打发我们了. 按照上面的写法,根本不知道  - (void)calendarEventReminderReceived:(NSNotificatio ...

随机推荐

  1. ACL2020 Contextual Embeddings When Are They Worth It 精读

    上下文嵌入(Bert词向量): 什么时候值得用? ACL 2018 预训练词向量 (上下文嵌入Bert,上下文无关嵌入Glove, 随机)详细分析文章 1 背景 图1 Bert 优点 效果显著 缺点 ...

  2. Python分析6000家破产IT公司

    前一阵有个字节跳动的程序员火了,年仅28岁实现了财务自由,宣布提前退休.最直接的原因是选择了一家发展前景很好的创业公司.当然平时我们经常能听到,某某人加入创业公司,xx年后公司上市,身价暴涨,财务自由 ...

  3. 趣讲 PowerJob 超强大的调度层,开始表演真正的技术了

    本文适合有 Java 基础知识的人群 作者:HelloGitHub-Salieri HelloGitHub 推出的<讲解开源项目>系列. 写在前面的碎碎念:终于到了万众期待的调度层原理了. ...

  4. JS中escape()、encodeURI()、encodeURIComponent()区别详解

    avaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decode ...

  5. JS DOM重点核心笔记

    DOM重点核心     文档对象模型,是W3C推荐的处理可扩展的标记语言的标准编程接口     我们主要针对与勇士的操作,主要有创建.增加.删除.修改.查询.属性操作.事件操作   三种动态创建元素的 ...

  6. GitLab 系列文章

    GitLab 系列文章 记录 GitLab 的相关文章 列表 Docker 搭建 GitLab GitLab CI/CD 配置 GitLab 配置模板 访问 GitLab 数据库 GitLab 转让所 ...

  7. MyBatisPlus配置日志,CRUD的使用

    配置日志 我们所有的sql在mybatisplus是不可见的,所以在开发中需要配置日志,开发完成后,就可以取消日志了,因为日志也是损耗资源的 #配置日志 mybatis-plus: configura ...

  8. Android Studio Gradle build 报错:Received status code 400 from server: Bad Request

    错误提示如下 Could not GET 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.1.2/ ...

  9. JavaScript正则、错误处理、操作表单

    一.正则表达式:用单个字符串描述或者匹配符合特定语句规则的字符串 一些字符序列组合在一起,可以简单也可以复杂模式的,可以去搜索,可以去替换 二.语法: /表达式/修饰符(可选) var para=/i ...

  10. (java)剑指offer二维数组中的查找

    在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从 上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. pu ...