📖 目录
-
前言
-
什么是观察者模式
-
案例背景:虚拟仿真水温实验
-
案例效果图(示意)
-
代码实现
-
5.1 被观察者:WaterHeater
-
5.2 观察者:ThermometerUI
-
5.3 观察者:ExperimentLogger
-
5.4 观察者:BoilingAlert
-
5.5 UI 控制:HeatButton
-
-
运行流程
-
注意事项总结
-
扩展思考
-
总结
1. 前言
在 虚拟仿真实验 或 教学类项目 中,经常会遇到类似的场景:
-
实验数据变化时,需要同时更新 UI、日志、提示系统。
-
如何做到 解耦,避免系统间的强依赖?
👉 答案就是:观察者模式(Observer Pattern)。
本文通过一个 Unity Demo 案例,带大家学习观察者模式在虚拟仿真中的应用。
2. 什么是观察者模式
观察者模式 :定义了一种 一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知。
在 Unity 中,通常通过 事件(event)或委托(delegate) 来实现。
3. 案例背景:虚拟仿真水温实验
我们实现一个 加热水温实验:
-
玩家点击按钮加热水温(被观察者)。
-
水温变化时:
-
温度计 UI 实时更新
-
实验日志记录变化
-
超过 100℃ 时提示"水已沸腾"
-
👉 这个场景中,"水温"就是 被观察者 ,UI/日志/提示系统就是 观察者。
4. 案例效果图(示意)
css
[按钮:加热]
↓
[当前温度:80℃] ← 温度计 UI 更新
[日志:温度变化为 80℃] ← 日志记录
[提示:未沸腾] ← 警告系统未触发
点击按钮后,温度升高 10℃,所有观察者自动收到通知。
5. 代码实现
5.1 被观察者:WaterHeater(加热器)
cs
using System;
using UnityEngine;
public class WaterHeater : MonoBehaviour
{
public event Action<int> OnTemperatureChanged; // 事件:温度变化通知
private int temperature = 20; // 初始温度
public void HeatUp()
{
temperature += 10;
Debug.Log($"[WaterHeater] 当前温度: {temperature}℃");
OnTemperatureChanged?.Invoke(temperature); // 通知所有观察者
}
public int GetTemperature() => temperature;
}
5.2 观察者:ThermometerUI(温度计 UI)
cs
using UnityEngine;
using UnityEngine.UI;
public class ThermometerUI : MonoBehaviour
{
[SerializeField] private Text temperatureText;
[SerializeField] private WaterHeater waterHeater;
private void OnEnable()
{
waterHeater.OnTemperatureChanged += UpdateUI;
}
private void OnDisable()
{
waterHeater.OnTemperatureChanged -= UpdateUI;
}
private void UpdateUI(int temperature)
{
temperatureText.text = $"温度: {temperature}℃";
}
}
5.3 观察者:ExperimentLogger(实验日志)
cs
using UnityEngine;
public class ExperimentLogger : MonoBehaviour
{
[SerializeField] private WaterHeater waterHeater;
private void OnEnable()
{
waterHeater.OnTemperatureChanged += LogTemperature;
}
private void OnDisable()
{
waterHeater.OnTemperatureChanged -= LogTemperature;
}
private void LogTemperature(int temperature)
{
Debug.Log($"[ExperimentLogger] 记录日志:温度变化为 {temperature}℃");
}
}
5.4 观察者:BoilingAlert(沸腾提示)
cs
using UnityEngine;
public class BoilingAlert : MonoBehaviour
{
[SerializeField] private WaterHeater waterHeater;
private void OnEnable()
{
waterHeater.OnTemperatureChanged += CheckBoiling;
}
private void OnDisable()
{
waterHeater.OnTemperatureChanged -= CheckBoiling;
}
private void CheckBoiling(int temperature)
{
if (temperature >= 100)
{
Debug.Log("[BoilingAlert] ⚠️ 水已沸腾!");
}
}
}
5.5 UI 控制:HeatButton(按钮)
cs
using UnityEngine;
using UnityEngine.UI;
public class HeatButton : MonoBehaviour
{
[SerializeField] private Button heatButton;
[SerializeField] private WaterHeater waterHeater;
private void Start()
{
heatButton.onClick.AddListener(() => waterHeater.HeatUp());
}
}
6. 运行流程
-
玩家点击 加热按钮 →
WaterHeater.HeatUp()
-
OnTemperatureChanged
事件触发 -
所有观察者收到通知:
-
ThermometerUI
更新 UI -
ExperimentLogger
写日志 -
BoilingAlert
检查是否沸腾
-
👉 解耦效果:
-
WaterHeater
只负责 通知,不关心谁在监听。 -
观察者们只关心自己逻辑,随时可新增/移除。
7. 注意事项总结
-
事件解绑 :
使用
OnDisable
取消订阅,避免内存泄漏或空引用错误。 -
事件为空判断 :
使用
OnTemperatureChanged?.Invoke(value)
,避免NullReferenceException
。 -
避免强依赖 :
WaterHeater
不直接调用 UI / 日志 / 提示,而是通过事件通知。
8. 扩展思考
-
可以新增 成绩统计系统,订阅水温变化来计算实验得分。
-
可以新增 数据上传系统,把实验数据同步到后台。
-
可以改为 ScriptableObject Event,进一步解耦 UI 和逻辑。
9. 总结
通过这个虚拟仿真案例,你学会了:
-
如何用 观察者模式 解耦系统之间的依赖
-
如何通过 事件机制 在 Unity 中实现一对多通知
-
如何把这个模式应用到虚拟仿真实验中(UI、日志、提示、成绩等系统)
👉 这就是 Unity 中观察者模式的最佳实践!