观察者模式(Observer Pattern)的核心是”发布-订阅”机制 ——— 让一个“事件源”(被观察者)在状态放生变化时, 自动通知所有”订阅者”(观察者), 且两者完全解耦(事件源不知道观察者的存在, 观察者也不依赖事件源的具体实现).
在Unity中, 它是处理跨系统事件通知的”神器”, 比如”玩家得分变化””角色受伤””卡关结束”等场景, 都能通过它避免代码耦合.
举个具体场景: 玩家得分事件通知
假设游戏中玩家得分时, 需要触发 3 个独立功能:
- 分数UI面板(
ScoreUI): 更新显示分数
- 成就系统(
AchievementSystem): 检查是否达成”得分 100分” “连续加分”等成就;
- 音效系统(
SoundSystem): 播放加分音效
如果不用观察者模式,
ScoreManager(得分管理)会直接调用这3个系统的方法(scoreUI.UpdateScore()\achievement.Check()), 导致:ScoreManager与其他系统强耦合, 修改任何一个系统都要改ScoreManager;
- 新增”积分排行榜”时, 需要修改
SocreManager代码, 违反开放 - 封闭原则.
观察者模式解决思路:
ScoreManager作为”事件源”, 只负责管理分数和发布”得分变化”事件;
- 分数UI\成就系统作为”观察者”, 订阅该事件;
- 得分变化时,
ScoreManager只需要通知所有订阅者, 无需关心谁在订阅.
观察者模式的核心角色
- 抽象主题(
ISubject): 定义事件源的统一接口(注册观察者\移除观察者\通知观察者).
- 具体主题(
Concrete Subject): 事件源的实际实现(如ScoreManager), 持有观察者列表, 状态变化时触发通知.
- 抽象观察者(
IObserver): 定义观察者统一接口(接受事件通知的方法).
- 具体观察者(Concrete Observer): 订阅事件的对象(如
Score UI\AchievementSystem), 实现接受通知后的逻辑.
代码实现步骤
- 定义抽象接口(解耦核心)
先定义
ISubject (事件源接口) 和IObserver(观察者接口), 让具体类依赖抽象:- 实现具体主题(事件源: 得分管理)
ScoreManager 负责管理分数, 当分数变化时, 通知所有已注册的观察者:- 实现具体观察者(订阅者: 响应逻辑)
每个需要相应”分数变化”的系统, 都是先
IObserver 接口, 专注于自己的逻辑:- 测试脚本(模式得分场景)
创建要给测试脚本, 模拟游戏中”击杀敌人加分”的逻辑:
Unity中配置与测试步骤
- 创建核心对象:
- 新建空对象
GameManager, 添加ScoreManager和SocreTester脚本
- 创建观察者对象:
- 新建 UI 文本(
TextMeshPro),命名ScoreText,添加ScoreUI脚本,将文本组件拖到_scoreText字段。 - 新建空对象
AchievementSystem,添加AchievementSystem脚本。 - 新建空对象
SoundSystem,添加AudioSource组件(赋值加分音效),再添加SoundSystem脚本,将AudioSource拖到_addScoreSound字段。
- 关联引用:
- 将
GameManager的ScoreManager组件, 拖到ScoreTester的_scoreManager字段.
- 运行测试:
- 运行后, 控制台会输出各种观察者的相应日志, 分数UI会实时更新, 音效会播放, 成就会自动解锁.
观察者模式的核心优势
- 解耦事件源与观察者:
ScoreManager不需要知道ScoreUI\AchievementSystem的存在, 只负责发布事件; 观察者也不用依赖ScoreManager的具体实现, 只需要订阅事件.
- 扩展性极强: 新增”积分呢排行榜”时, 只需新建
RankSystem类实现IObserver, 注册到ScoreManager即可, 无需修改任何现有代码.
- 灵活控制订阅关系: 可以在运行时动态注册/移除观察者(比如暂停时移除音效观察者, 恢复后重新注册).
- 统一事件分发: 一次事件触发, 所有订阅者自动相应, 无需手动调用多个系统.
Unity中的原生替代方案
Unity自带的
UnityEvent(或Event)本质上也是观察者模式的封装, 用法更简洁(无需手动定义 ISubject和IObserver), 比如将ScoreManager修改为:然后再观察者脚本中, 直接通过 Inspector将
OnScoreChangedEvent 绑定到响应方法(或代码绑定OnScoreChangedEvent.AddListener(OnScoreChanged)), 功能完全一致, 更适合快速开发.总结
观察模式就像”微信公众号” ——— 公众号(事件源
ScoreManager )发布文章(分数变化), 所有订阅的用户(观察者 ScoreUI \ AchievementSystem )都会收到通知, 公众号不用知道订阅者是谁, 订阅者也可以随时取消关注. 在Unity中, 它是处理跨系统事件\减少代码耦合的”必备工具”.