事件监听模式
一、概述
事件监听模式(Event-Listener Pattern)不属于基本设计模式,是 观察者模式 的一种实现。提供一种基于 Event 的通讯模式。
二、分析
事件监听模式包括一个 EventListener(类似于观察者 Observer ),EventManager(事件管理器,类似于主题 Subject),还有一个 Event 表示事件,可以理解为观察者模式中消息通知 Notify。
观察者模式 参考博文:观察者模式
在开发中常用于各个系统之间的通讯,降低系统间的耦合性。
三、代码实现
源码:https://github.com/WarZhan/DesignPatterns/tree/master/EventListenerPattern
- 事件类
_context :事件发起者,在开发中通常使用单例作为发起者,方便全局访问,且具有唯一性
/// <summary>
/// 事件
/// </summary>
public class Event
{
private object _context;
public object Context
{
get { return _context; }
}
private string _name;
public string Name
{
get { return _name; }
}
private object[] _data;
public object[] Data
{
get { return _data; }
}
public Event(object context, string name, object[] data = null)
{
_context = context;
_name = name;
_data = data;
}
}
- 事件监听器
使用 params 可变参数作为回调参数方便拓展。
public delegate void EventListener(params object[] args);
- 事件管理器
用来管理事件的注册、注销以及广播
核心部分:
(1)使用消息队列 Queue<Event> _queueEvent 保存消息列表,保证消息的有序性
(2)使用 Hashtable _tableListener 保存同一消息源的相关监听回调,提高访问效率
(3)Update 方法定时推送消息
public class EventManager
{
private static readonly Lazy<EventManager> _instance =
new Lazy<EventManager>(() => new EventManager());
public static EventManager Instance
{
get { return _instance.Value; }
}
private EventManager() { }
private Hashtable _tableListener = null;
private Queue<Event> _queueEvent = null;
public void Init()
{
_tableListener = new Hashtable();
_queueEvent = new Queue<Event>();
}
/// <summary>
/// 添加监听事件
/// </summary>
/// <param name="context"></param>
/// <param name="eventName"></param>
/// <param name="listener"></param>
public void AddEventListener(object context, string eventName, EventListener listener)
{
if (context == null || listener == null || string.IsNullOrEmpty(eventName))
{
Console.WriteLine("Event Manager: AddListener failed due to no listener or event name specified.");
}
else
{
List<EventListener> list = _GetEventListenerList(context, eventName, true);
// 去重
if (list.Exists(it => it == listener))
{
Console.WriteLine("Event Manager: Listener: " + context + " - " + listener.GetType().ToString() + " is already in list for event: " + eventName);
}
else
{
list.Add(listener);
}
}
}
public void RemoveEventListener(object context, string eventName, EventListener listener)
{
if (_tableListener.ContainsKey(context))
{
List<EventListener> list = _GetEventListenerList(context, eventName);
if (null != list)
{
list.Remove(listener);
}
}
}
/// <summary>
/// 发送消息时 先保存到队列
/// </summary>
/// <param name="newEvent"></param>
public void SendMessage(Event newEvent)
{
_queueEvent.Enqueue(newEvent);
}
private void _TriggerEvent(Event eventData)
{
// 这里从其他线程调用的需要转换下
List<EventListener> list = _GetEventListenerList(eventData.Context, eventData.Name);
if (null != list)
{
list.ForEach(it => it(eventData.Data));
}
}
public void Update()
{
while (_queueEvent.Count > 0)
{
Event item = _queueEvent.Dequeue();
_TriggerEvent(item);
}
}
private List<EventListener> _GetEventListenerList(object context, string eventName, bool createIfNotExist = false)
{
if (!_tableListener.ContainsKey(context))
{
if (createIfNotExist)
{
_tableListener.Add(context, new Dictionary<string, List<EventListener>>());
}
else
{
return null;
}
}
Dictionary<string, List<EventListener>> dic = _tableListener[context] as Dictionary<string, List<EventListener>>;
if (!dic.ContainsKey(eventName))
{
if (createIfNotExist)
{
dic[eventName] = new List<EventListener>();
return dic[eventName];
}
else
{
return null;
}
}
else
{
return dic[eventName];
}
}
}
- Demo
class Program
{
static void Main(string[] args)
{
// 初始化管理器
EventManager.Instance.Init(); // 事件管理器
CreaterManager.Instance.Init(); // 生产者
PackagerManager.Instance.Init(); // 打包者
// 启动计时器 每 100 毫秒 更新一次
Timer threadTimer = new Timer(_Update, null, 0, 100);
CreaterManager.Instance.CreateProduct(); // 开始生产
Console.ReadKey();
}
private static void _Update(object state)
{
EventManager.Instance.Update();
}
}
四、UML 图
参考资料
[1] EventManager:https://github.com/Archanium/ngj/blob/master/Unity/Assets/EventManager.cs
[2] 事件监听模式:https://blog.csdn.net/qq_25673113/article/details/53244571
欢迎关注个人公众号,实时推送最新博文!