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)


​最后我们放松一下眼睛

相关推荐
吴梓穆3 小时前
Unity EasyAR入门教程
unity
GesLuck6 小时前
C#开发实例1—彩票选号
开发语言·c#
neter.asia8 小时前
C# 窗体应用程序嵌套web网页,基于谷歌浏览器内核(含源码)
开发语言·c#
小猪写代码9 小时前
C语言:递归函数(新增)
算法·c#
两水先木示9 小时前
【Unity3D】ECS入门学习(七)缓存区组件 IBufferElementData
学习·unity·ecs
EQ-雪梨蛋花汤11 小时前
【WebAR-图像跟踪】在Unity中基于Imagine WebAR实现AR图像识别
unity·游戏引擎·ar
sukalot12 小时前
windows C#-在查询中返回元素属性的子集
开发语言·c#
向宇it13 小时前
【从零开始入门unity游戏开发之——C#篇32】C#其他不常用的泛型数据结构类、顺序存储和链式存储
java·开发语言·数据结构·unity·c#·游戏引擎
阿泽不想掉光头发14 小时前
C#实现调用DLL 套壳读卡程序(桌面程序开发)
java·开发语言·后端·websocket·http·c#
-凌凌漆-14 小时前
【C#】WPF设置Separator为垂直方向
c#