zoukankan      html  css  js  c++  java
  • 【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 (二) : 引入中间层NotificationCenter

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明。如果你喜欢这篇文章,请点【推荐】。谢谢!

    QQ图片20140529123319

    一对多的观察者模式机制有什么缺点?

    想要查看完整源代码,还是访问这个项目的GitHub:https://github.com/MrNerverDie/Unity-Flappy-Bird

    如果你对如何在Unity中使用事件/委托机制还不太了解,建议您查看我的前一篇文章:【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信

    在前一篇博客里面,我们写到:【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信,其中使用了EventHandler这个委托作为通用的事件类型,实现了一对多的观察者模式。但是这样做有什么缺点呢?我们还是举前文所说的小鸟撞上管道为例:

    bird1

    在这里面,小鸟撞倒管道时,小鸟会发送一个 产生碰撞的 消息传送给所有观察者,那么,如果我们新加入一个名为天鹅,它也能在天上飞,那么我们就要在它的类内部实现一个同样功能的 产生碰撞的 消息传送给所有观察者,这样就产生了代码重复,软件中解决代码重复的问题一般使用的事引入中间层的办法,所以我仿照Cocos2d-x中的CCNotificationCenter写了一个CCNotificationCenter来存储各种消息并转发来当作中间层。

    引入中间层 -- NotificationCenter

    NotificationCenter基本的设计思路是基于MessageDispatcher模式的,即使用一个字典(Dictionary)来记录各种需要转发的信息,以及这些信息的观察者,然后再恰当的时候进行消息的转发。NotificationCenter还应当提供观察者订阅和取消订阅的方法。

    NotificationCenter是基于单件模式的,它在第一次被调用GetInstance方法时被初始化的,使用单件的原因是要让NotificationCenter的生命期比任何一个观察者都长,这样才不会出现NotificationCenter为空的情况。

    在下面的代码里,我把INotificationCenter做成抽象类的原因是:希望通过这个继承这个类来创建多个子类,比如可以创建UINotificationCenter,BattleNotificationCenter,TradeNotificationCenter。来进行消息的分组。

    下面我把自己的代码分享一下,供大家参考:

    using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    
    // NotificationCenter的拓展类,在这里弄出多个INotificationCenter的子类,
    // 分别处理不同的消息转发,便于消息分组
    public class NotificationCenter : INotificationCenter
    {
        private static INotificationCenter singleton;
    
        private event EventHandler GameOver;
        private event EventHandler ScoreAdd;
    
        private NotificationCenter()
            : base()
        {
            // 在这里添加需要分发的各种消息
            eventTable["GameOver"] = GameOver;
            eventTable["ScoreAdd"] = ScoreAdd;
        }
    
        public static INotificationCenter GetInstance()
        {
            if (singleton == null)
                singleton = new NotificationCenter();
            return singleton;
        }
    }
    
    // NotificationCenter的抽象基类
    public abstract class INotificationCenter
    {
    
        protected Dictionary<string, EventHandler> eventTable;
    
        protected INotificationCenter()
        {
            eventTable = new Dictionary<string, EventHandler>();
        }
    
        // PostNotification -- 将名字为name,发送者为sender,参数为e的消息发送出去
        public void PostNotification(string name)
        {
            this.PostNotification(name, null, EventArgs.Empty);
        }
        public void PostNotification(string name, object sender)
        {
            this.PostNotification(name, name, EventArgs.Empty);
        }
        public void PostNotification(string name, object sender, EventArgs e)
        {
            if (eventTable[name] != null)
            {
                eventTable[name](sender, e);
            }
        }
    
        // 添加或者移除了一个回调函数。
        public void AddEventHandler(string name, EventHandler handler)
        {
            eventTable[name] += handler;
        }
        public void RemoveEventHandler(string name, EventHandler handler)
        {
            eventTable[name] -= handler;
        }
    
    }

    对观察者进行抽象化 -- 引入Observer

    在加入了NotificationCenter之后,我们要面对的下一个问题就是,我们的每一个观察者都需要在自己的Start方法中添加回调函数,在OnDestroy方法中取消回调函数,那么,我们可以把这部分的代码抽象在一个Observer组件中,使用另一个字典记载下所有的该GameObject注册的回调函数,在Observer的OnDestroy方法里面一次全部取消订阅。代码如下:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using System;
    
    public class Observer : MonoBehaviour {
        private INotificationCenter center;
        private Dictionary<string, EventHandler> handlers;
    
        void Awake() {
            handlers = new Dictionary<string, EventHandler>();
            center = NotificationCenter.GetInstance();
        }
    
        void OnDestroy() {
            foreach (KeyValuePair<string, EventHandler> kvp in handlers) {
                center.RemoveEventHandler(kvp.Key, kvp.Value);
            }
        }
    
        public void AddEventHandler(string name, EventHandler handler) {
            center.AddEventHandler(name, handler);
            handlers.Add(name, handler);
        }
    }
  • 相关阅读:
    Hive Left Join 中 On 与 Where 的区别
    Matplotlib 中文显示方框 最简单解决方案
    Pandas DataFrame 取消科学计数法打印
    Hive中小表与大表关联(join)的性能分析
    ceiling和floor转化
    Tensorflow 错误:The flag 'xxx' is defined twice
    移动端测试
    Selenium处理alert/confirm/prompt提示框,无头浏览器,规避网站监测
    selenium关于断言的使用和获取input的值
    Selenium之用例流程设计
  • 原文地址:https://www.cnblogs.com/neverdie/p/3790879.html
Copyright © 2011-2022 走看看