订阅发布者模式/观察者模式-Unity C#代码框架

2023-12-20 17:18

本文主要是介绍订阅发布者模式/观察者模式-Unity C#代码框架,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    什么是订阅发布者模式?简单的说,比如我看见有人在公交车上偷钱包,于是大叫一声“有人偷钱包”(发送消息),车上的人听到(接收到消息)后做出相应的反应,比如看看自己的钱包什么的。其实就两个步骤,注册消息与发送消息。

    为了适应项目需要,写了一个通用订阅发布者模式的通用模块,有了这样一个模块,项目里面其他模块之间的耦合性也将大大降低。

   话不多说,直接上代码。

   消息分发中心:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 消息分发中心.
/// </summary>
public class DispatcherCenter
{private static Logger logger = LogHelper.GetLogger("DispatcerCenter");private static DispatcherCenter instance;public static DispatcherCenter Instance{get{if (instance == null){instance = new DispatcherCenter();}return instance;}}private Dictionary<int, List<Observer>> map = new Dictionary<int, List<Observer>>();/// <summary>/// 发送消息./// </summary>/// <param name="type">消息类型.</param>/// <param name="msg">消息内容.</param>public void SendNotification(int type, object msg){if (map.ContainsKey(type)){List<Observer> observers = map[type];foreach (Observer obs in observers){Notification notice = new Notification(type, msg);if(obs.handler != null){obs.handler(notice);}}}else{if (msg == null){logger.Error("分发消息失败,未注册该消息!!! Type: " + type + " Msg is null.");}else{logger.Error("分发消息失败,未注册该消息!!! Type: " + type + " Msg: " + msg);}}}/// <summary>/// 注册消息./// </summary>/// <param name="type">消息类型.</param>/// <param name="handler">收到消息的回调.</param>public void RegisterObserver(int type, NotificationHandler handler){List<Observer> observers = null;if (map.TryGetValue(type, out observers)){foreach (Observer obs in observers){if (obs.handler == handler){//logger.Debug("该回调已经注册,不能重复注册!");return;}}observers.Add(new Observer(type, handler));}else{observers = new List<Observer>();observers.Add(new Observer(type, handler));map.Add(type, observers);}}/// <summary>/// 移除消息./// </summary>/// <param name="type">消息类型.</param>/// <param name="handler">收到消息的回调.</param>public void RemoveObserver(int type, NotificationHandler handler){List<Observer> observers = map[type];if (map.TryGetValue(type, out observers)){foreach (Observer obs in observers){if(obs.handler == handler){observers.Remove(obs);//bool result = observers.Remove(obs);//logger.Debug("消息移除是否成功: " + result);return;}}logger.Error("移除失败,未找到该回调!!! Type: " + type);}else{logger.Error("移除失败,未注册该消息!!! Type: " + type);}}
}

 订阅者:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//接收到消息的回调.
public delegate void NotificationHandler(Notification notice);/// <summary>
/// 观察者.
/// </summary>
public class Observer
{public NotificationHandler handler;public Observer() { }public Observer(int type, NotificationHandler handler){this.handler += handler;}
}

消息类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 消息类.
/// </summary>
public class Notification
{private int type;private object msg;public int Type { get { return type; } }public object Msg { get { return msg; } }public Notification(int type, object msg){this.type = type;this.msg = msg;}public override string ToString(){if (msg != null){return string.Format("Type:{0} Msg:{1}", type, msg.ToString());}return string.Format("Type:{0} Msg is null", type);}
}

消息:(我用的是枚举表示,然后强转为int值来识别是哪个消息,枚举值不能重复)

/// <summary>
/// 消息枚举.
/// </summary>
public class NotificationEnum
{public enum ModelNotices{SEPARATE = 0,MERGE}public enum OtherNotice{OTHER1 = 101,OTHER2}
}

那么如何使用呢?

还是看代码,首先在Notifications中添加要注册的消息号,然后在合适时候调用RegisterNotifications()注册消息,在NotificationHandler()中根据消息号做出相应的操作。在不需要再观察消息的时候移除消息RemoveNotifications();

using UnityEngine;public class Test : MonoBehaviour
{private void Awake(){RegisterNotifications();}private void OnDestory(){RemoveNotifications();}private void Update(){if (Input.GetKeyDown(KeyCode.F1)){UnityEngine.Debug.Log("---------->>>> 分离消息.");//消息内容可以是任何东西,如int值,类    DispatcherCenter.Instance.SendNotification((int)NotificationEnum.ModelNotices.SEPARATE, null);}if (Input.GetKeyDown(KeyCode.F2)){UnityEngine.Debug.Log("---------->>>> 合并消息.");//消息内容可以是任何东西,如int值,类            DispatcherCenter.Instance.SendNotification((int)NotificationEnum.ModelNotices.MERGE, null);}//if (Input.GetKeyDown(KeyCode.F1))//{//    Debug.Log("Test1 注册消息.");//    RegisterNotifications();//}//if (Input.GetKeyDown(KeyCode.Keypad1))//{//    Debug.Log("Test1 移除消息.");//    RemoveNotifications();//}}#region 消息相关//需注册的消息. TODOprivate int[] Notifications{get{return new int[]{(int)NotificationEnum.ModelNotices.SEPARATE,(int)NotificationEnum.ModelNotices.MERGE};}}private void RegisterNotifications(){for (int i = 0; i < Notifications.Length; i++){DispatcherCenter.Instance.RegisterObserver(Notifications[i], NotificationHandler);}}private void RemoveNotifications(){for (int i = 0; i < Notifications.Length; i++){DispatcherCenter.Instance.RemoveObserver(Notifications[i], NotificationHandler);}}//收到消息的回调 TODOprivate void NotificationHandler(Notification notice){if (notice.Type == (int)NotificationEnum.ModelNotices.SEPARATE){UnityEngine.Debug.Log("Test1收到零件分离的消息." + notice.ToString());}else if (notice.Type == (int)NotificationEnum.ModelNotices.MERGE){UnityEngine.Debug.Log("Test1收到零件合并的消息." + notice.ToString());}}#endregion}

 

这篇关于订阅发布者模式/观察者模式-Unity C#代码框架的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/516819

相关文章

C#中Guid类使用小结

《C#中Guid类使用小结》本文主要介绍了C#中Guid类用于生成和操作128位的唯一标识符,用于数据库主键及分布式系统,支持通过NewGuid、Parse等方法生成,感兴趣的可以了解一下... 目录前言一、什么是 Guid二、生成 Guid1. 使用 Guid.NewGuid() 方法2. 从字符串创建

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

Spring 框架之Springfox使用详解

《Spring框架之Springfox使用详解》Springfox是Spring框架的API文档工具,集成Swagger规范,自动生成文档并支持多语言/版本,模块化设计便于扩展,但存在版本兼容性、性... 目录核心功能工作原理模块化设计使用示例注意事项优缺点优点缺点总结适用场景建议总结Springfox 是

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)