Unity 观察者模式(实例详解)

文章目录

    • 简介
      • [示例1 - 简单的文本更新通知](#示例1 - 简单的文本更新通知)
      • [示例2 - 多观察者监听游戏分数变化](#示例2 - 多观察者监听游戏分数变化)
      • [示例3 - 事件系统实现观察者模式](#示例3 - 事件系统实现观察者模式)
      • [示例4 - 泛型观察者和可序列化的事件系统](#示例4 - 泛型观察者和可序列化的事件系统)
      • 示例5 - 使用C#委托简化版

简介

在Unity中实现观察者模式,我们可以创建一个Subject(目标/主题)类,它负责维护订阅者列表,并且当其状态改变时通知所有观察者。下面通过5个代码示例来详细展示如何在Unity C#脚本中应用观察者模式:

示例1 - 简单的文本更新通知

csharp 复制代码
using System.Collections;
using System.Collections.Generic;

// 观察者接口
public interface IObserver
{
    void OnUpdate(string message);
}

// 被观察者接口
public interface IObservable
{
    void Register(IObserver observer);
    void Remove(IObserver observer);
    void NotifyObservers(string message);
}

// 具体的被观察者类
public class TextDisplay : MonoBehaviour, IObservable
{
    private List<IObserver> observers = new List<IObserver>();

    public void Register(IObserver observer)
    {
        observers.Add(observer);
    }

    public void Remove(IObserver observer)
    {
        observers.Remove(observer);
    }

    public void NotifyObservers(string message)
    {
        foreach (var observer in observers)
        {
            observer.OnUpdate(message);
        }
    }

    // 模拟状态改变
    public void UpdateText(string newText)
    {
        Debug.Log("Text has been updated to: " + newText);
        NotifyObservers(newText);
    }
}

// 具体的观察者类
public class ConsoleLogger : MonoBehaviour, IObserver
{
    public void OnUpdate(string message)
    {
        Debug.Log("Console Logger received update: " + message);
    }
}

// 使用示例
public class GameManager : MonoBehaviour
{
    public TextDisplay display;
    public ConsoleLogger logger;

    void Start()
    {
        display.Register(logger);
        display.UpdateText("Hello, World!");
    }
}

示例2 - 多观察者监听游戏分数变化

csharp 复制代码
public interface IScoreObserver : IObserver
{
    void OnScoreChanged(int newScore);
}

public class ScoreManager : MonoBehaviour, IObservable
{
    private List<IScoreObserver> scoreObservers = new List<IScoreObserver>();

    public void Register(IScoreObserver observer)
    {
        scoreObservers.Add(observer);
    }

    public void Remove(IScoreObserver observer)
    {
        scoreObservers.Remove(observer);
    }

    public void NotifyScoreObservers(int newScore)
    {
        foreach (var observer in scoreObservers)
        {
            observer.OnScoreChanged(newScore);
        }
    }

    public void IncreaseScore(int points)
    {
        int currentScore = GetTotalScore(); // 假设这是一个获取当前分数的方法
        int newScore = currentScore + points;
        SetTotalScore(newScore); // 假设这是一个设置总分数的方法
        NotifyScoreObservers(newScore);
    }
}

public class ScoreUI : MonoBehaviour, IScoreObserver
{
    public void OnScoreChanged(int newScore)
    {
        GetComponent<Text>().text = "Score: " + newScore;
    }
}

public class HighScoreTracker : MonoBehaviour, IScoreObserver
{
    public void OnScoreChanged(int newScore)
    {
        if (newScore > PlayerPrefs.GetInt("HighScore"))
        {
            PlayerPrefs.SetInt("HighScore", newScore);
        }
    }
}

// 使用示例
public class GameInitializer : MonoBehaviour
{
    public ScoreManager scoreManager;
    public ScoreUI scoreUI;
    public HighScoreTracker highScoreTracker;

    void Start()
    {
        scoreManager.Register(scoreUI);
        scoreManager.Register(highScoreTracker);
        // 游戏过程中调用scoreManager.IncreaseScore()增加分数
    }
}

示例3 - 事件系统实现观察者模式

csharp 复制代码
using UnityEngine.Events;

public class SubjectWithEvent : MonoBehaviour
{
    public UnityEvent<string> OnTextUpdated;

    public void UpdateText(string newText)
    {
        Debug.Log("Text has been updated to: " + newText);
        OnTextUpdated.Invoke(newText);
    }
}

public class ObserverUsingEvent : MonoBehaviour
{
    public SubjectWithEvent subject;

    void Start()
    {
        subject.OnTextUpdated.AddListener(OnTextUpdatedHandler);
    }

    void OnDestroy()
    {
        subject.OnTextUpdated.RemoveListener(OnTextUpdatedHandler);
    }

    void OnTextUpdatedHandler(string message)
    {
        Debug.Log("Received text update: " + message);
    }
}

示例4 - 泛型观察者和可序列化的事件系统

csharp 复制代码
[System.Serializable]
public class GenericEvent<T> : UnityEvent<T>
{
}

public class ObservableGeneric<T> : MonoBehaviour
{
    public GenericEvent<T> OnStateChanged;

    public T State { get; private set; }

    public void ChangeState(T newState)
    {
        State = newState;
        OnStateChanged?.Invoke(newState);
    }
}

public class ObserverForGeneric<T> : MonoBehaviour
{
    public ObservableGeneric<T> observable;

    public void Awake()
    {
        observable.OnStateChanged.AddListener(StateChangedHandler);
    }

    public void OnDestroy()
    {
        observable.OnStateChanged.RemoveListener(StateChangedHandler);
    }

    void StateChangedHandler(T newState)
    {
        Debug.Log($"New state received: {newState}");
    }
}

// 使用示例
public class ExampleUsage : MonoBehaviour
{
    public ObservableGeneric<int> healthObservable;
    public ObserverForGeneric<int> healthObserver;

    void Start()
    {
        healthObserver.observable = healthObservable;
    }
}

示例5 - 使用C#委托简化版

csharp 复制代码
public class SimpleObservable
{
    public delegate void MessageEventHandler(string message);

    public event MessageEventHandler OnMessageEvent;

    public void SendMessage(string message)
    {
        OnMessageEvent?.Invoke(message);
    }
}

public class SimpleObserver : MonoBehaviour
{
    public SimpleObservable observable;

    void Start()
    {
        observable.OnMessageEvent += HandleMessageEvent;
    }

    void OnDestroy()
    {
        observable.OnMessageEvent -= HandleMessageEvent;
    }

    void HandleMessageEvent(string message)
    {
        Debug.Log("Received message: " + message);
    }
}

// 使用示例
public class SimpleExample : MonoBehaviour
{
    public SimpleObservable messageSource;
    public SimpleObserver messageRecipient;

    void Start()
    {
        messageRecipient.observable = messageSource;
        messageSource.SendMessage("Hello from the Observable");
    }
}

以上每个示例都展示了观察者模式的基本原理:当被观察者的状态发生改变时,它会通知所有已注册的观察者进行相应的响应或更新操作。

python推荐学习汇总连接:
50个开发必备的Python经典脚本(1-10)

50个开发必备的Python经典脚本(11-20)

50个开发必备的Python经典脚本(21-30)

50个开发必备的Python经典脚本(31-40)

50个开发必备的Python经典脚本(41-50)


​最后我们放松一下眼睛

相关推荐
北京理工大学软件工程2 小时前
C#111
开发语言·c#
DaLiangChen6 小时前
Unity 实用工具:动态绘制物体边界包围盒(支持屏幕固定线宽)
unity·游戏引擎
张老师带你学6 小时前
Unity 食物 农产品相关
科技·游戏·unity·游戏引擎·模型
mxwin6 小时前
Unity Custom Interpolators与半透明阴影的原理与实战
unity·游戏引擎·shader
晴夏。6 小时前
UE5第三人称模板实现及相关引擎源码分析
unity·ue5·游戏引擎·ue
雪飞鸿8 小时前
ArrayPoolWrapper简洁、安全的ArrayPool
c#·.net·.net core·原创
海盗12349 小时前
C#上位机开发-S7协议通信
开发语言·c#
FeBaby9 小时前
ReentrantLock 与 synchronized 底层实现对比图解
开发语言·c#
烟话610 小时前
C# 内存机制详解:值类型、引用类型与 String 的不可变性
java·jvm·c#