设计模式 --- 观察者模式

观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。

优点:

​​1.解耦性强​​:

​​观察者(订阅者)与主题(发布者)通过抽象接口通信,不直接依赖具体实现,​​修改主题或观察者的代码时,无需影响对方,提升代码可维护性。

2.​​动态订阅机制​​:

​​观察者可随时注册或注销,运行时灵活调整事件响应,支持热插拔功能,增强系统扩展性。

3.​​一对多通信高效​​:

一个主题状态变化可同时通知多个观察者,避免重复调用逻辑,提升事件处理效率。

​​4.支持事件驱动架构​​:

通过事件总线(Event Bus)实现全局通信, ​​简化跨模块通信,适合复杂系统交互。

缺点:

1.​性能开销​​:

高频事件(如每帧更新)或大量观察者时,遍历通知列表耗时(物理引擎的CollisionEvent在百个对象碰撞时,触发千次通知)。

​​优化​​ :

1.使用事件合并(如积累多次位置更新后批量通知)。

2.异步处理(将事件推送到队列,分帧处理)。

2.​​内存泄漏风险​​:

​​观察者未正确注销时,Subject(主题者)持有其引用导致无法回收(Unity中,UI面板销毁前未取消订阅事件)。

​​优化​​ :

使用弱引用(WeakReference)或者使用扩展方法在MonoBehaviour绑定取消事件注册的方法,使其在OnDestroy时调用取消注册方法。

cs 复制代码
public static void UnregisterOnDestroy(this MonoBehaviour obj, Action unsubscribe) {
    obj.gameObject.AddComponent<OnDestroyDispatcher>().OnDestroyEvent += unsubscribe;
}

class OnDestroyDispatcher : MonoBehaviour {
    public event Action OnDestroyEvent;
    void OnDestroy() => OnDestroyEvent?.Invoke();
}

注:弱引用的使用 (会加一篇Unity中弱引用的测试使用的文章)。

3.​​事件顺序不可控​​:

​​观察者处理事件的顺序依赖注册顺序,可能导致逻辑错误。

​​优化 ​​:

引入优先级字段,按优先级排序观察者。

4.​调试困难​​:

​​问题​​:事件流分散,难以追踪事件触发源头和传递链路。

​​优化 ​​:

添加事件日志:记录每个事件的发布者和订阅者。

说明例子:

1.UML图:

2.实现:

1.实现Subject(主题者)基类:

cs 复制代码
    public abstract class Subject
    {
        List<Observer> m_Observers = new List<Observer>();

        //加入观察者
        public void Attach(Observer theObserver)
        {
            m_Observers.Add(theObserver);
        }

        //删除观察者
        public void Detach(Observer theObserver)
        {
            m_Observers.Remove(theObserver);
        }

        //通知所有观察者
        public void Notify()
        {
            foreach (Observer theObserver in m_Observers)
            {
                theObserver.Update();
            }
        }
    }

2.实现Observer(观察者)基类:

cs 复制代码
    public abstract class Observer
    {
        public abstract void Update();
    }

3.实现具体Subject:

cs 复制代码
    public class ConcreteSubject : Subject
    {
        string m_SubjectState;

        public void SetState(string state)
        {
            this.m_SubjectState = state;
            this.Notify();
        }

        public string GetState()
        {
            return this.m_SubjectState;
        }
    }

4.实现具体Observer:

cs 复制代码
   //实现Observer1
   public class ConcreteObserver1 : Observer
   {

       ConcreteSubject m_Subject = null;

       public ConcreteObserver1(ConcreteSubject theSubject)
       {
           this.m_Subject = theSubject;
       }

       public override void Update()
       {
           Debug.Log("ConcreteObserver1.Update");
           //获取Subject状态
           Debug.Log("ConcreteObserver1 : Subject 当前主题:" + m_Subject.GetState());
       }
   }

   //实现Observer2
   public class ConcreteObserver2 : Observer
   {

       ConcreteSubject m_Subject = null;

       public ConcreteObserver2(ConcreteSubject theSubject)
       {
           this.m_Subject = theSubject;
       }

       public override void Update()
       {
           Debug.Log("ConcreteObserver2.Update");
           //获取Subject状态
           Debug.Log("ConcreteObserver2 : Subject 当前主题:" + m_Subject.GetState());
       }
   }

游戏中使用场景:

​​1.成就/统计系统​​ :监听关键游戏事件(击杀、死亡、收集)--->玩家击杀Boss后解锁成就。

​​2.UI更新 ​​:将UI元素与游戏数据解耦--->血量变化时自动刷新血条UI。

​​3.跨系统通信​​ :避免系统间直接引用--->背包系统物品使用后通知技能系统。

​​4.AI行为触发​​ :基于事件触发的敌人反应---->玩家进入警戒范围触发敌人警报。

​​5.网络同步​​:将本地事件广播给其他客户端--->玩家位置同步事件。

总结:

观察者模式的核心价值​​在于解耦和动态通信,但其性能、内存和调试问题需谨慎处理。

在游戏开发中,观察者模式适用于以下场景:

1.需要松耦合的跨系统通信。

2.需要动态处理大量事件类型。

3.需要支持模块化扩展(如MOD系统)。

参考书籍:

《Hands-On Game Development Patterns with Unity 2019》

《设计模式与游戏完美开发》

相关推荐
高晶1 小时前
ARM 嵌入式 Linux 系统 U-Boot 开发与移植实战M
设计模式·程序员
geovindu6 小时前
rust: Chain of Responsibility Pattern
开发语言·后端·设计模式·rust·责任链模式·行为模式
拆房老料7 小时前
【第四部分:Agentic 智能体设计模式】15.为什么 Agent 也需要设计模式
人工智能·设计模式·ai·ai-native
geovindu8 小时前
rust: Chain of Responsibility Pattern (续)
开发语言·后端·设计模式·rust·责任链模式·行为模式
Lost of 程序猿9 小时前
责任链模式实战:审批流里“层层把关“的艺术
后端·设计模式·asp.net·责任链模式
希洛兔1 天前
状态模式详解:让对象随内部状态自动改变行为
java·设计模式·状态模式
博风1 天前
7、设计模式应用举例:策略模式:加密、解密文件
设计模式·策略模式
4SAPI1 天前
Provider Adapter设计模式:如何让AI应用支持多个模型
网络·人工智能·设计模式
geovindu1 天前
rust: pool Pattern
开发语言·后端·设计模式·rust·对象池简写模式
高晶1 天前
ARM 嵌入式 Linux 开发:从体系结构到 LED 点亮实战
设计模式·程序员