07 事件监听模式

事件监听模式

一、概述

事件监听模式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

欢迎关注个人公众号,实时推送最新博文!
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值