Unity 设计模式-观察者模式(Observer Pattern)详解

观察者模式

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。这种模式用于事件处理系统,当某个对象发生改变时,依赖该对象的其他对象能够及时响应。

在观察者模式中,主要有两个角色:

  1. 被观察者(Subject):状态发生变化的对象,它维护了一组观察者列表,并在状态发生变化时通知它们。
  2. 观察者(Observer):依赖被观察者的对象,它注册到被观察者上,并在被观察者状态变化时得到通知。

1、什么时候使用观察者模式

事件系统:需要实现基于事件驱动的系统,许多UI系统使用观察者模式来创建按钮点击,值变化等事件

数据同步:当某个对象的状态改变时,依赖它的其他对象需要同步更新。

系统中存在一对多的依赖关系:例如,一个对象的变化需要通知多个对象做出反应,典型的例子包括股票价格变化通知、新闻订阅系统等。

通知机制:在某些情况下,多个模块需要接收到某个变化的信息(如游戏事件、社交媒体通知等)。

2、使用观察者模式的好处

解耦合:观察者和被观察者之间的耦合度低。被观察者只知道观察者实现了某些接口,而无需了解它们的具体实现细节。
灵活性:可以动态添加或移除观察者,系统的扩展性好。
提高代码的可维护性:将状态的变化与相应的反应分开,使代码更易于维护和修改。
响应式更新:观察者模式允许系统中的多个对象自动响应某个对象的状态变化,无需显式调用每个依赖对象。

3、使用时的注意事项

性能问题:当观察者数量过多时,每次状态改变都需要通知所有观察者,这可能会引起性能问题。
避免循环依赖:如果观察者在更新过程中再次触发了被观察者的通知,可能会导致循环调用或死锁。
顺序问题:多个观察者对同一事件做出响应时,要注意观察者之间的顺序依赖,可能会导致某些观察者未按预期更新。
内存泄漏问题:要确保观察者可以正确地从被观察者中移除,以避免内存泄漏问题。

4、我现在用通俗的例子来给大家描述一下观察者模式

想象有一个人气明星,比如周杰伦~。杰伦有非常多的歌迷,这些歌迷对他的新专辑翘首以盼(话说距离上次伟作已经过去两年了……),都在关注着杰伦的专辑动向,一有点风吹草动大家就会沸腾。那么,观察杰伦的歌迷们就是【观察者】,被歌迷们观察的杰伦就是【被观察者】。

在观察者模式中,被观察者的状态发生改变时,就会向所有的观察者们发送通知,观察者们就可以根据这个通知做出各自相应的行为。类比到杰伦和歌迷上,就是当杰伦发新专辑时(简直天方夜谭!),他会在各种社交媒体、音乐软件上发布这个消息,而所有关注杰伦的歌迷在看到这一消息后,有的掏出钱包,有的奔走相告,有的因激动而变身狒狒:吼吼哇哇!

当然,观察者模式中还有一个很重要的概念:【主题】,我更习惯称呼它为【中间体】。中间体是观察者和被观察者之间的桥梁,就好像一个代理人,负责管理有哪些观察者正在观察自己代理的被观察者。每当被观察者状态改变发送消息时,消息首先到达中间体,再由中间体传递出去。在杰伦和歌迷的比喻中,中间体就好比是社交媒体、音乐平台。

在 Unity 中使用 观察者模式

为了演示如何在 Unity 中使用 观察者模式。

我们将实现一个示例:当玩家接触到一个触发器(Trigger)时,游戏会通知观察者更新,例如改变颜色、显示文本等。

这个示例将演示如何使用观察者模式管理多个对象对玩家触发事件做出反应。

1、定义观察者接口

首先,我们定义一个观察者接口,所有的观察者类都需要实现这个接口。

public interface IObserver
{void OnNotify();
}
2、定义被观察者类

然后我们定义一个被观察者类。在这个示例中,被观察者是一个触发器,当玩家接触触发器时,它会通知所有观察者。

using System.Collections.Generic;
using UnityEngine;public class TriggerSubject : MonoBehaviour
{private List<IObserver> observers = new List<IObserver>();// 注册观察者public void RegisterObserver(IObserver observer){observers.Add(observer);}// 移除观察者public void RemoveObserver(IObserver observer){observers.Remove(observer);}// 通知所有观察者public void NotifyObservers(){foreach (IObserver observer in observers){observer.OnNotify();}}// Unity 的触发器事件,当玩家接触触发器时调用private void OnTriggerEnter(Collider other){if (other.CompareTag("Player")){NotifyObservers();}}
}
3、实现观察者类

接下来我们创建几个不同的观察者类,每个观察者类会响应触发器的通知。在这个例子中,我们将创建两个观察者:

  • 一个会改变颜色
  • 一个会显示文本

3.1 观察者 1:改变颜色的观察者

using UnityEngine;public class ColorObserver : MonoBehaviour, IObserver
{public Renderer objectRenderer;public void OnNotify(){// 随机改变对象的颜色objectRenderer.material.color = new Color(Random.value, Random.value, Random.value);Debug.Log("ColorObserver: Color changed!");}
}

3.2 观察者 2:显示文本的观察者

using UnityEngine;
using UnityEngine.UI;public class TextObserver : MonoBehaviour, IObserver
{public Text messageText;public void OnNotify(){// 显示通知文本messageText.text = "Player triggered the event!";Debug.Log("TextObserver: Text updated!");}
}
4、在场景中使用观察者模式

现在我们在 Unity 场景中设置以下内容:

  1. 创建一个空的 GameObject,命名为 Trigger,并将 TriggerSubject 脚本附加到该对象上。同时,在该对象上添加一个 BoxCollider,并勾选 Is Trigger。
  2. 创建两个 3D 物体(如立方体或球体),并附加 ColorObserver 脚本到其中一个物体,记得将 objectRenderer 变量拖入到 Inspector 中。
  3. 创建一个 UI 文本,附加 TextObserver 脚本,并将 messageText 变量拖入 Inspector。
  4. 在游戏的 Start() 函数中,注册观察者。
using UnityEngine;public class GameManager : MonoBehaviour
{public TriggerSubject triggerSubject;public ColorObserver colorObserver;public TextObserver textObserver;void Start(){// 注册观察者triggerSubject.RegisterObserver(colorObserver);triggerSubject.RegisterObserver(textObserver);}void OnDestroy(){// 在销毁时移除观察者,避免内存泄漏triggerSubject.RemoveObserver(colorObserver);triggerSubject.RemoveObserver(textObserver);}
}
5、运行示例

1.将 GameManager 脚本挂载到 Unity 场景中的一个空对象上。
2.在 GameManager 中的 Inspector 窗口,将 triggerSubject、colorObserver 和 textObserver 分别拖入相应的字段。
3.运行游戏,当玩家接触 Trigger 对象时,注册的观察者将会被通知:
   物体的颜色会发生变化。
   UI 文本会显示 "Player triggered the event!"。

6、示例分析
  • 触发器 (TriggerSubject) 是被观察者,当玩家接触它时,它会调用 NotifyObservers() 方法通知所有的观察者。
  • 观察者 (ColorObserver 和 TextObserver) 实现了 IObserver 接口,并在 OnNotify() 方法中定义了各自的行为。
  • 通过这种设计,任何新增的观察者只需要实现 IObserver 接口,并注册到 TriggerSubject 中,而不需要修改已有的代码。

通过这个示例,我们可以看到如何在 Unity 中运用 观察者模式,处理多个对象对同一事件的响应。这种模式在处理游戏事件、状态变化等场景中十分有用,尤其是在复杂的游戏系统中。

今天是2024年12月3日

重复一段毒鸡汤来勉励我和你

你的对手在看书

你的仇人在磨刀

你的闺蜜在减肥

隔壁的老王在练腰

而你在干嘛?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/888837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文:IoU Loss for 2D/3D Object Detection

摘要&#xff1a;在2D/3D目标检测任务中&#xff0c;IoU (Intersection-over- Union)作为一种评价指标&#xff0c;被广泛用于评价不同探测器在测试阶段的性能。然而&#xff0c;在训练阶段&#xff0c;通常采用常见的距离损失(如L1或L2)作为损失函数&#xff0c;以最小化预测值…

vue.js学习(day 20)

综合案例&#xff1a;购物车 数据渲染 构建cart购物车模块 准备后端接口服务环境 请求数据存入vuex cart.js // 新建购物车模块 import axios from axios export default {namespaced: true,state () {return {// 购物车数据 [{},{}]list: []}},mutations: {updateList (…

RAG系统分类、评估方法与未来方向

分享一篇RAG综述&#xff1a;Retrieval-Augmented Generation for Large Language Models: A Survey&#xff0c;主要想了解一下RAG的评估方法&#xff0c;分享给大家。 文章目录 一、RAG分类二、评估方法三、未来方向 一、RAG分类 RAG分类&#xff1a;Navie RAG、Advanced RA…

美国大选后,用HMM模型做特斯拉股价波动解析

作者&#xff1a;老余捞鱼 原创不易&#xff0c;转载请标明出处及原作者。 写在前面的话&#xff1a;本文主要探讨如何利用高斯隐马尔可夫模型&#xff08;HMM&#xff09;预测股票价格&#xff0c;我们将分步进行说明&#xff1a;包括数据准备、特征选择、训练 HMM 模型、最后…

VSCode(四)CMake调试

1. 工具准备 1.1 C环境插件 1.2 CMake插件 2. Cmake工程 2.1 创建项目文件夹 ex:CMAKE_TEST 2.2 创建CMake工程 &#xff08;shift ctl P), 选择"CMAKE: Quick Start": 2.3 填写project name: (ex: test_cmake) 2.4 选择”Executable“ 项目文件内会自动…

从 HTML 到 CSS:开启网页样式之旅(七)—— CSS浮动

从 HTML 到 CSS&#xff1a;开启网页样式之旅&#xff08;七&#xff09;—— CSS浮动 前言一、浮动的简介1.没有浮动的代码和效果2.加入浮动的代码和效果 二、元素浮动后的特点1. 脱离文档流2.宽高特性&#xff1a;3.共用一行&#xff1a;4.margin 特性&#xff1a;5.区别于行…

微信小程序实现图片拖拽调换位置效果 -- 开箱即用

在编写类似发布朋友圈功能的功能时&#xff0c;需要实现图片的拖拽排序&#xff0c;删除图片等功能。 一、效果展示 **博主的小程序首页也采用了该示例代码&#xff0c;可以在威信中搜索&#xff1a;我的百宝工具箱 二、示例代码 1.1、在自己的小程序中创建组件 1.2、组件…

通过 FRP 实现 P2P 通信:控制端与被控制端配置指南

本文介绍了如何通过 FRP 实现 P2P 通信。FRP&#xff08;Fast Reverse Proxy&#xff09;是一款高效的内网穿透工具&#xff0c;能够帮助用户突破 NAT 和防火墙的限制&#xff0c;将内网服务暴露到公网。通过 P2P 通信方式&#xff0c;FRP 提供了更加高效、低延迟的网络传输方式…

php7.4安装pg扩展-contos7

今天接到一个需求&#xff0c;就是需要用thinkphp6链接pg(postgresql)数据库。废话不多说&#xff0c;直接上操作步骤 一、安装依赖 yum install -y sqlite-devel libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcurl-devel libjpeg libjpeg-dev…

CentOS7.X 安装RustDesk自建服务器实现远程桌面控制

参照文章CentOS安装RustDesk自建服务器中间总有几个位置出错&#xff0c;经实践做个记录防止遗忘 一 环境&工具准备 1.1 阿里云轻量服务器、Centos7系统、目前最高1.1.11版本rustdesk-server-linux-amd64.zip 1.2 阿里云轻量服务器–安全组–开放端口&#xff1a;TCP(21…

TCP Analysis Flags 之 TCP Spurious Retransmission

前言 默认情况下&#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态&#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时&#xff0c;会对每个 TCP 数据包进行一次分析&#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…

Java线程的interrupt中断、wait-notify/all(源码级分析)

实例方法&#xff1a; interrupt()方法是设置结束阻塞(sleep、wait等)&#xff0c;并且设置中断标记true isInterrupted()判断当前是否中断 静态方法&#xff1a; Thread.interrupted():调用这个方法的线程中断标记位还原为false 那么好&#xff0c;既然上面的方法作用是清…

Burp Suite 实战指南:Proxy 捕获与修改流量、HTTP History 筛选与分析

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

12月第1周AI资讯

阅读时间:3-4min 更新时间:2024.12.2-2024.12.6 目录 OpenAI CEO Sam Altman 预告“12天OpenAI”系列活动 腾讯HunyuanVideo:130亿参数的开源视频生成模型 李飞飞的World Labs发布空间智能技术预览版 中科院联手腾讯打造“AI带货王”AnchorCrafter OpenAI CEO Sam Alt…

从零开始学TiDB(1) 核心组件架构概述

首先TiDB深度兼容MySQL 5.7 1. TiDB Server SQL语句的解析与编译&#xff1a;首先一条SQL语句最先到达的地方是TiDB Server集群&#xff0c;TiDB Server是无状态的&#xff0c;不存储数据&#xff0c;SQL 发过来之后TiDB Server 负责 解析&#xff0c;优化&#xff0c;编译 这…

记录一次使用git无权限的问题排查

正常的配置了公私钥之后&#xff0c;在gitlab中也存储了配对的公钥&#xff0c;但当使用git clone 时&#xff0c;总是报无权限 由于在这台机器中添加了多个公私钥&#xff0c;有点复杂&#xff0c;我们可以使用命令 ssh -vvvT 调试一下 ssh -vvvT yourGitlabAddr

python调用GPT-4o实时音频 Azure OpenAI GPT-4o Audio and /realtime

发现这块网上信息很少&#xff0c;记录一下 微软azure入口 https://learn.microsoft.com/zh-cn/azure/ai-services/openai/realtime-audio-quickstart?pivotsprogramming-language-ai-studio sdk文档 https://github.com/azure-samples/aoai-realtime-audio-sdk?tabread…

fastadmin 后台插件制作方法

目录 一&#xff1a;开发流程 二&#xff1a;开发过程 &#xff08;一&#xff09;&#xff1a;后台功能开发 &#xff08;二&#xff09;&#xff1a;功能打包到插件目录 &#xff08;三&#xff09;&#xff1a;打包插件 &#xff08;四&#xff09;&#xff1a;安装插件…

Kafka单机及集群部署及基础命令

目录 一、 Kafka介绍1、kafka定义2、传统消息队列应用场景3、kafka特点和优势4、kafka角色介绍5、分区和副本的优势6、kafka 写入消息的流程 二、Kafka单机部署1、基础环境2、iptables -L -n配置3、下载并解压kafka部署包至/usr/local/目录4、修改server.properties5、修改/etc…

Docker部署的gitlab升级的详细步骤(升级到17.6.1版本)

文章目录 一、Gitlab提示升级信息二、老版本的docker运行gitlab命令三、备份老版本Gitlab数据四、确定升级路线五、升级(共分3个版本升级)5.1 升级第一步(17.1.2 > 17.3.7)5.2 升级第二步(17.3.7 > 17.5.3)5.3 升级第三步(17.5.3 > 17.6.1) 六、web端访问gitlab服务 一…