一、简介

       当在Unity中应用观察者模式时,通常是为了实现一种解耦和灵活性较强的事件机制。观察者模式允许一个对象(称为主题)维护一组依赖于它的对象(称为观察者),当主题的状态发生变化时,所有观察者都能够得到通知并进行相应的处理。

二、观察者模式的优势

  1. 松耦合:
            观察者模式通过将主题和观察者解耦,使得它们之间的依赖关系更加松散。主题并不需要知道观察者的具体类别,只需知道它们实现了相同的接口或继承了相同的基类。这使得系统更容易维护和扩展。
  2. 可维护性和可扩展性:
            由于主题和观察者之间的解耦,系统更容易维护。在不修改主题的情况下,可以轻松地添加或删除观察者,从而扩展系统的功能。
  3. 事件驱动的设计:
           观察者模式天然支持事件驱动的设计。主题的状态变化会触发事件,通知所有观察者进行相应的处理。这在Unity中特别有用,例如在游戏中处理用户输入、游戏状态变化等。
  4. 多播通知:
           观察者模式允许一个主题同时通知多个观察者。这意味着可以有多个对象独立地响应主题的变化,而不需要主题知道观察者的具体数量或类型。
  5. 解耦 UI 和数据:
           在游戏开发中,观察者模式经常用于解耦UI和底层数据。当数据发生变化时,通过观察者模式通知UI进行更新,使得UI可以保持与数据的同步。
  6. 易于理解和维护:
           观察者模式是一种经典的设计模式,因此它的使用方式是广泛接受的。这使得代码更易于理解,也更容易维护,因为开发人员可以更容易地理解和预测代码的行为。

        总体而言,观察者模式在Unity中的应用能够提高代码的灵活性、可维护性和可扩展性,是一种强大的设计模式。

三、观察者模式的具体适用案例

观察者模式在Unity当中的适用场景有很多,下面主要介绍的是事件管理器的应用,直接上代码。

using Mr.Le.Utility.Singleton;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

namespace Mr.Le.Utility.Manager
{
    /// <summary>
    /// 事件管理器
    /// </summary>
    public class EventCenterManager : NoMonoSingleton<EventCenterManager>
    {
        /// <summary>
        /// 用于里氏替换的接口
        /// </summary>
        private interface IEventInfo
        {

        }

        //事件集合
        private Dictionary<string, IEventInfo> _events = new Dictionary<string, IEventInfo>();


        #region 无参事件

        private class EventInfo : IEventInfo
        {
            public UnityAction action;

            /// <summary>
            /// 构造函数添加事件
            /// </summary>
            /// <param name="call"></param>
            public EventInfo(UnityAction call)
            {
                action += call;
            }
        }

        /// <summary>
        /// 添加事件监听
        /// </summary>
        /// <param name="command"></param>
        /// <param name="call"></param>
        public void AddEventListener(object command, UnityAction call)
        {
            string name = command.GetType().Name + "_" + command;

            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo).action += call;
            }
            else
            {
                _events.Add(name, new EventInfo(call));
            }
        }

        /// <summary>
        /// 移除指定事件的指定监听
        /// </summary>
        /// <param name="command"></param>
        /// <param name="call"></param>
        public void RemoveEventListener(object command, UnityAction call)
        {
            string name = command.GetType().Name + "_" + command;
            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo).action -= call;
            }
            else
            {
                Debug.LogError($"{name}事件不存在!");
                return;
            }
        }

        /// <summary>
        /// 移除指定事件的所有监听
        /// </summary>
        /// <param name="command"></param>
        public void RemoveAllEventListeners(object command)
        {
            string name = command.GetType().Name + "_" + command;

            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo).action = null;
            }
            else
            {
                Debug.LogError($"{name}事件不存在!");
                return;
            }
        }

        /// <summary>
        /// 呼叫事件
        /// </summary>
        /// <param name="command"></param>
        public void CallEvent(object command)
        {
            string name = command.GetType().Name + "_" + command;
            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo).action?.Invoke();
            }
            else
            {
                Debug.LogError($"{name}事件不存在!");
                return;
            }
        }

        #endregion

        #region 有参事件

        private class EventInfo<T> : IEventInfo
        {
            public UnityAction<T> action;

            /// <summary>
            /// 构造函数添加事件
            /// </summary>
            /// <param name="call"></param>
            public EventInfo(UnityAction<T> call)
            {
                action += call;
            }
        }

        /// <summary>
        /// 添加事件监听
        /// </summary>
        /// <param name="command"></param>
        /// <param name="call"></param>
        public void AddEventListener<T>(object command, UnityAction<T> call)
        {
            string name = command.GetType().Name + "_" + command;

            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo<T>).action += call;
            }
            else
            {
                _events.Add(name, new EventInfo<T>(call));
            }
        }

        /// <summary>
        /// 移除指定事件的指定监听
        /// </summary>
        /// <param name="command"></param>
        /// <param name="call"></param>
        public void RemoveEventListener<T>(object command, UnityAction<T> call)
        {
            string name = command.GetType().Name + "_" + command;
            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo<T>).action -= call;
            }
            else
            {
                Debug.LogError($"{name}事件不存在!");
                return;
            }
        }

        /// <summary>
        /// 移除指定事件的所有监听
        /// </summary>
        /// <param name="command"></param>
        public void RemoveAllEventListeners<T>(object command)
        {
            string name = command.GetType().Name + "_" + command;

            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo<T>).action = null;
            }
            else
            {
                Debug.LogError($"{name}事件不存在!");
                return;
            }
        }

        /// <summary>
        /// 呼叫事件
        /// </summary>
        /// <param name="command"></param>
        public void CallEvent<T>(object command, T value)
        {
            string name = command.GetType().Name + "_" + command;
            if (_events.ContainsKey(name))
            {
                (_events[name] as EventInfo<T>).action?.Invoke(value);
            }
            else
            {
                Debug.LogError($"{name}事件不存在!");
                return;
            }
        }

        #endregion
    }
}
测试代码:
无参事件:

被观察类:

public class Observer : MonoBehaviour
{
    private void OnEnable()
    {
        EventCenterManager.Instance.AddEventListener("事件1", TestFunc);
    }

    private void OnDisable()
    {
        EventCenterManager.Instance.RemoveEventListener("事件1", TestFunc);
    }

    private void TestFunc()
    {
        Debug.Log("这是一个无参事件的测试方法");
    }
}

 调用事件:

public class Player : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        EventCenterManager.Instance.CallEvent("事件1");
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

有参事件:

被观察者类

public class Observer : MonoBehaviour
{
    private void OnEnable()
    {
        EventCenterManager.Instance.AddEventListener<bool>("事件2", TestFunc);
    }

    private void OnDisable()
    {
        EventCenterManager.Instance.RemoveEventListener<bool>("事件2", TestFunc);
    }

    private void TestFunc(bool value)
    {
        if (value)
            Debug.Log("这是一个真消息!");
        else
            Debug.Log("这是一个假消息!");
    }
}

调用事件:

public class Player : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        EventCenterManager.Instance.CallEvent("事件2",true);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

         通过以上示例,你可以更好地理解在Unity中如何使用观察者模式来实现一种灵活且可维护的设计。

         希望这篇文章对你理解和应用观察者模式有所帮助。如果有任何疑问或建议,请在评论区留言。

更多推荐