一个在Unity中使用的观察者模式的消息传递机制。
原文链接:http://wiki.unity3d.com/index.php/NotificationCenterGenerics#Update_Notes
NotificationCenter使用在Unity中提供了一个简单并且强大的消息传递机制. 一个object可以注册为observer并且当有消息发出时接受某种类型的消息. 当通知类型在某处定义, 所有此消息类型的被注册的observer将会接收发生了的消息,和相关的数据.
这个系统允许一个对象传达他们的状态和事件到另一个对象, 每个接收通知的对象并不需要直接持有引用.当一个事件发生时对象可以很简单的发送它,任何一个感兴趣的对象都可以注册去接收事件.
使用方法
这是一个自动实例化的单例类. 不需要附加到一个对象上. 放入项目资源中并且通过调用DefaultCenter使用. 这个静态方法会自动创建一个游戏对象, 添加一个 NotificationCenter 组件, 并且创建一个它的引用.
通过访问 PostNotification 方法去发送事件:
NotificationCenter.DefaultCenter().PostNotification(this, "OnBumperCollision"); NotificationCenter.DefaultCenter().PostNotification(this, "OnBumperCollision", anyObject); NotificationCenter.DefaultCenter().PostNotification(new Notification(this, "OnBumperCollision")); NotificationCenter.DefaultCenter().PostNotification(new Notification(this, "OnBumperCollision", anyObject));
有几个PostNotification() 方法, 所有都是有效的. 它仅需要两个参数:发送者和通知名称. 他可以接受各种数据对象. 任何东西都可以被传递. 例如, OnBumperCollision消息能发送关于collision的信息, 或者是Collision 对象. 通常数据对象最好是使用Hashtable, 以便它可以包含各种各样的信息.
PostNotification()也可以被调用通过传递特别的参数, 或者是传递一个Notification 对象. Notification 对象可以被继承从而创建一个简化的数据对象. Notification 对象必须持有 sender, notification 名字, 和一个数据对象(可选的).
观察者通过调用AddObserver 方法接受通知:
NotificationCenter.DefaultCenter().AddObserver(this, "OnBumperCollision");
DefaultCenter() 是一个静态方法,可以返回一个通知中心是实例. 如果它不存在, 会自动实例化一个. AddObserver() 接受两个参数一个是希望接受通知的对象, 令一个是用于接受的通知名称. 被注册的通知是一个方法当事件发生时会被执行.
通过 RemoveObserver() 方法移除一个观察者:
NotificationCenter.DefaultCenter().RemoveObserver(this, "OnBumperCollision");
RemoveObserver() 方法从指定的通知的观察者列表中移除一个观察者.
想要接收通知, 只需要实现一个和通知名称一样的方法即可:
function OnBumperCollision (notification: Notification) { Debug.Log("Received notification from: " + notification.sender); if (notification.data == null) Debug.Log("And the data object was null!"); else Debug.Log("And it included a data object: " + notification.data); }
通知方法要接收一个 Notification 对象. 它包含三个属性:发送者,通知的名称,和一个可选的数据对象。
源码:
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; // NotificationCenter is used for handling messages between GameObjects. // GameObjects can register to receive specific notifications. When another objects sends a notification of that type, all GameObjects that registered for it and implement the appropriate message will receive that notification. // Observing GameObjects must register to receive notifications with the AddObserver function, and pass their selves, and the name of the notification. Observing GameObjects can also unregister themselves with the RemoveObserver function. GameObjects must request to receive and remove notification types on a type by type basis. // Posting notifications is done by creating a Notification object and passing it to PostNotification. All receiving GameObjects will accept that Notification object. The Notification object contains the sender, the notification type name, and an option hashtable containing data. // To use NotificationCenter, either create and manage a unique instance of it somewhere, or use the static NotificationCenter. // We need a static method for objects to be able to obtain the default notification center. // This default center is what all objects will use for most notifications. We can of course create our own separate instances of NotificationCenter, but this is the static one used by all. public class NotificationCenter : MonoBehaviour { private static NotificationCenter defaultCenter; public static NotificationCenter DefaultCenter () { // If the defaultCenter doesn't already exist, we need to create it if (!defaultCenter) { // Because the NotificationCenter is a component, we have to create a GameObject to attach it to. GameObject notificationObject = new GameObject("Default Notification Center"); // Add the NotificationCenter component, and set it as the defaultCenter defaultCenter = notificationObject.AddComponent<NotificationCenter>(); DontDestroyOnLoad(defaultCenter); } return defaultCenter; } // Our hashtable containing all the notifications. Each notification in the hash table is an ArrayList that contains all the observers for that notification. Hashtable notifications = new Hashtable(); // AddObserver includes a version where the observer can request to only receive notifications from a specific object. We haven't implemented that yet, so the sender value is ignored for now. public void AddObserver (Component observer, String name) { AddObserver(observer, name, null); } public void AddObserver (Component observer, String name, object sender) { // If the name isn't good, then throw an error and return. if (name == null || name == "") { Debug.Log("Null name specified for notification in AddObserver."); return; } // If this specific notification doens't exist yet, then create it. if (!notifications.ContainsKey(name)) { notifications[name] = new List<Component>(); } // if (!notifications[name]) { // notifications[name] = new List<Component>(); // } List<Component> notifyList = (List<Component>)notifications[name]; // If the list of observers doesn't already contain the one that's registering, then add it. if (!notifyList.Contains(observer)) { notifyList.Add(observer); } } // RemoveObserver removes the observer from the notification list for the specified notification type public void RemoveObserver (Component observer, String name) { List<Component> notifyList = (List<Component>)notifications[name]; //change from original // Assuming that this is a valid notification type, remove the observer from the list. // If the list of observers is now empty, then remove that notification type from the notifications hash. This is for housekeeping purposes. if (notifyList != null) { if (notifyList.Contains(observer)) { notifyList.Remove(observer); } if (notifyList.Count == 0) { notifications.Remove(name); } } } // PostNotification sends a notification object to all objects that have requested to receive this type of notification. // A notification can either be posted with a notification object or by just sending the individual components. public void PostNotification (Component aSender, String aName) { PostNotification(aSender, aName, null); } public void PostNotification (Component aSender, String aName, object aData) { PostNotification(new Notification(aSender, aName, aData)); } public void PostNotification (Notification aNotification) { // First make sure that the name of the notification is valid. if (aNotification.name == null || aNotification.name == "") { Debug.Log("Null name sent to PostNotification."); return; } // Obtain the notification list, and make sure that it is valid as well List<Component> notifyList = (List<Component>)notifications[aNotification.name]; //change from original if (notifyList == null) { Debug.Log("Notify list not found in PostNotification."); return; } // Clone list, so there won't be an issue if an observer is added or removed while notifications are being sent notifyList = new List<Component>(notifyList); // Create an array to keep track of invalid observers that we need to remove List<Component> observersToRemove = new List<Component>(); //change from original // Itterate through all the objects that have signed up to be notified by this type of notification. foreach (Component observer in notifyList) { // If the observer isn't valid, then keep track of it so we can remove it later. // We can't remove it right now, or it will mess the for loop up. if (!observer) { observersToRemove.Add(observer); } else { // If the observer is valid, then send it the notification. The message that's sent is the name of the notification. observer.SendMessage(aNotification.name, aNotification, SendMessageOptions.DontRequireReceiver); } } // Remove all the invalid observers foreach (Component observer in observersToRemove) { notifyList.Remove(observer); } } } // The Notification class is the object that is sent to receiving objects of a notification type. // This class contains the sending GameObject, the name of the notification, and optionally a hashtable containing data. public class Notification { public Component sender; public String name; public object data; public Notification (Component aSender, String aName) { sender = aSender; name = aName; data = null; } public Notification (Component aSender, String aName, object aData) { sender = aSender; name = aName; data = aData; } }