当前位置: 首页 > news >正文

Unity中设计模式

单例模式

什么是单例模式

  1. 确保一个类只有一个实例
  2. 有一个全局访问点【static】

用途:

  • 当多个对象需要共享同一资源【GameManager,AudioManager】时,用单例可以避免重复创建和资源冲突。
  • 避免频繁创建和销毁重量级对象,降低内存占用和性能开销。

有两种常见形式

  • 懒汉
  • 饿汉

区别在于实例创建的时机

懒汉式

在第一次调用获取实例的方法时才创建对象,实现了延迟加载,但在多线程环境下需要处理线程安全问题(如加锁、双重检查锁或静态内部类等方式)。

public class BaseManager<T> where T : new() { private static T instance; public static T GetInstance() { if (instance == null) instance = new T(); return instance; } }

饿汉式

在类加载时就已经完成实例的创建,天生线程安全,但可能造成资源浪费(如果一直未被使用)。

public class BaseManager<T> where T : new() { private static T instance = new T(); // 类加载时即创建实例 public static T GetInstance() { return instance; } }

缓存池【对象池模式】

在对象需要频繁创建和销毁的情况下使用,提高复用性,来优化性能。

简易缓存池

using System.Collections; using System.Collections.Generic; using UnityEngine; public class easyPoolMgr : BaseMgr<easyPoolMgr> { public Dictionary<string, List<GameObject>> pooldic = new Dictionary<string, List<GameObject>>(); public GameObject GetObj(string name) { GameObject obj = null; if (pooldic.ContainsKey(name)&&pooldic[name].Count > 0)//这里pooldic[name].Count > 0条件忘记加了 { obj = pooldic[name][0]; pooldic[name].RemoveAt(0); //Remove和RemoveAt不一样,RemoveAt传入的是下标 } else { obj = GameObject.Instantiate(Resources.Load<GameObject>(name)); obj.name = name; } //激活 obj.SetActive(true); return obj; } public void PushObj(string name, GameObject obj) { if (pooldic.ContainsKey(name)) { pooldic[name].Add(obj); } else { pooldic.Add(name, new List<GameObject>() { obj }); } //失活 obj.SetActive(false); } }

进阶缓存池

using System.Collections; using System.Collections.Generic; using UnityEngine; public class poolData { public GameObject fatherContainer; public List<GameObject> poolList; public poolData(GameObject obj, GameObject poolContainer) { poolList = new List<GameObject>(); fatherContainer = new GameObject(obj.name); fatherContainer.transform.SetParent(poolContainer.transform); //容易忘 //入池的时候发现,没有对应池子。-----》就要生成池子,调用构造函数------》因为是入池子的时候触发的所以要触发一次入池 PushObj(obj); } //执行取对象方法 public GameObject GetObj() { GameObject obj = null; //取出第一个 obj = poolList[0]; poolList.RemoveAt(0); //解绑父子关系 obj.transform.parent = null; //激活 obj.SetActive(true); return obj; } //执行入池方法 public void PushObj(GameObject obj) { //失活 obj.SetActive(false); //绑定父子关系 obj.transform.parent = fatherContainer.transform; //入池 poolList.Add(obj); } } public class poolManager : BaseMgr<poolManager> { //对象池名和对象池存储空间的键值对 public Dictionary<string, poolData> pooldic = new Dictionary<string, poolData>(); //对象池根节点 public GameObject poolContainer; //调度池中对象,做判断语句 public GameObject GetObj(string name) { GameObject obj = null; //如果有指定的池子且池子里有对象 if (pooldic.ContainsKey(name) && pooldic[name].poolList.Count > 0) { //执行取对象方法 obj = pooldic[name].GetObj(); } else { //如果没有指定的对象,创建一个对象 obj = GameObject.Instantiate(Resources.Load<GameObject>(name)); //该对象改名为路径名 obj.name = name; } //返回对象 return obj; } //入池调度 public void PushObj(string name, GameObject obj) { //忘记了 //判断是否有对象池根节点,如没有,则创建一个 if (poolContainer == null) { poolContainer = new GameObject("poolContainer"); } //如果有对应的存储空间 if (pooldic.ContainsKey(name)) { //执行入池操作 pooldic[name].PushObj(obj); } else { //如果没有,则通过池名和根节点---创造一个池子 pooldic.Add(name, new poolData(obj, poolContainer)); } } //清理对象池--切场景时调用 public void clear() { pooldic.Clear(); poolContainer = null; } }

事件中心【观察者模式】

简易事件中心

using System.Collections.Generic; using UnityEngine.Events; public class easyEventCenter : BaseMgr<easyEventCenter> { //UnityAction<T1,T2> 的意思是委托存储的是传入参数为T1,T2的函数。且UnityAction是没有返回值的。如果要有返回值得使用Func private Dictionary<string,UnityAction<object>>eventDic = new Dictionary<string,UnityAction<object>>(); //添加事件监听----------->可以在其他脚本的Start调用 public void AddEventListener(string name, UnityAction<object> action) { //有没有对应的监听 //有监听 if (eventDic.ContainsKey(name)) { eventDic[name] += action; } else//无监听 { eventDic.Add(name,action); } } //移除事件监听,防止内存泄露------->可以在其他脚本的OnDestroy调用 public void RemoveEventListener(string name, UnityAction<object> action) { if (eventDic.ContainsKey(name)) { eventDic[name] -= action; } } //事件触发 public void EventTrigger(string name,object info) { if (eventDic.ContainsKey(name)) { eventDic[name].Invoke(info); } } //主要用在场景切换 public void Clea() { eventDic.Clear(); } }

优化事件中心【里氏替换原则优化拆箱装箱】

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public interface IEventInfo { } public class EventInfo<T> : IEventInfo { public UnityAction<T> actions; public EventInfo(UnityAction<T> action) { this.actions += action; } } public class EventInfo : IEventInfo { public UnityAction actions; public EventInfo(UnityAction action) { this.actions += action; } } public class EventCenter : BaseManager<EventCenter> { //key--事件的名字 //value--对应的是监听这个事件对应的委托函数们 private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>(); //添加事件监听,传事件名和委托函数 public void AddEventListener<T>(string name, UnityAction<T> action) { if (eventDic.ContainsKey(name)) //该事件有监听的情况 { (eventDic[name] as EventInfo<T>).actions += action; } else //该事件没有监听的情况 { eventDic.Add(name, new EventInfo<T>(action)); } } //重载添加事件监听--无参数 public void AddEventListener(string name, UnityAction action) { if (eventDic.ContainsKey(name)) //该事件有监听的情况 { (eventDic[name] as EventInfo).actions += action; } else //该事件没有监听的情况 { eventDic.Add(name, new EventInfo(action)); } } //取消监听--非常重要,不移除监听可能会导致内存泄露 public void RemoveEventListener<T>(string name, UnityAction<T> action) { if (eventDic.ContainsKey(name)) { (eventDic[name] as EventInfo<T>).actions -= action; } } //重载取消监听--无参数 public void RemoveEventListener(string name, UnityAction action) { if (eventDic.ContainsKey(name)) { (eventDic[name] as EventInfo).actions -= action; } } //事件触发,传要触发的事件名 public void EventTrigger<T>(string name,T info) { if (eventDic.ContainsKey(name)) { if ((eventDic[name] as EventInfo<T>).actions != null) { (eventDic[name] as EventInfo<T>).actions.Invoke(info); } } } //重载事件触发--无参数 public void EventTrigger(string name) { if (eventDic.ContainsKey(name)) { if ((eventDic[name] as EventInfo).actions != null) { (eventDic[name] as EventInfo).actions.Invoke(); } } } //清空事件中心,可以用于场景切换防内存泄露 public void Clear() { eventDic.Clear(); } }
http://www.jsqmd.com/news/585460/

相关文章:

  • Jetbrains官宣下一代构建工具!
  • SEO_10个实用的SEO优化技巧,快速提升网站排名
  • Windows任务栏透明化神器:TranslucentTB让你的桌面瞬间高级
  • Phi-3-mini-128k-instruct应用场景:数据分析师自然语言转Python代码助手
  • 如何通过QtScrcpy实现跨平台键鼠映射?4个技术要点让PC精准操控Android游戏
  • 告别高成本投流,亿煤 GEO 如何用 AI 搜索实现长效获客?
  • 配置多区域OSPF
  • RePKG完全指南:Wallpaper Engine资源提取与TEX转换终极方案
  • Z-Image-GGUF模型融合实验:与其他开源模型混合生成新奇风格
  • 掌握上下文工程:新手程序员必备技能,轻松提升大模型代理能力(收藏版)
  • 脚本猫 油猴 ScriptCat+JavaScript脚本js快速通过学习率
  • 3步解决Windows视频播放难题:LAV Filters开源解码器终极方案
  • 告别论文内耗!2026九大AI神器合集,3天搞定本科毕业论文
  • Python 面向对象高级核心知识点(超详细完整版)
  • 23.【RTL_Synthesis】Static Timing Analysis Fundamentals(静态时序分析基础)
  • 原神帧率解锁终极指南:如何免费突破60帧限制畅玩高刷新率游戏
  • STM32船舶负载平衡监控系统设计与实现
  • 下载神器!5M开源软件,2026谷歌、天地图、高德、ArcGIS影像...任意下载
  • 突破网盘下载瓶颈:八大平台直链获取工具的全方位指南
  • Qwen3-ASR-0.6B技术解析:强制对齐模型的时间戳预测原理
  • OpenClaw跨平台控制:Phi-3-mini远程操作手机实测
  • 全域数学框架下拓扑物理与N体问题的统一理 论—兼论宇宙稳态拓扑的实验验证(乖乖数学)
  • 突破手游操控边界:QtScrcpy虚拟按键功能实现电脑精准操控的5个技术要点
  • 面向对象编程(OOP)基础超详细教程 | 小白也能看懂的Python版
  • Dvwa靶场通关攻略心得(Brute Force)
  • GLM-4-9B-Chat-1M镜像升级路径:从GLM-4-9B-Chat到1M版本的权重转换与验证
  • AI时代下的AOSP构建:从“效率黑洞”到“分钟级交付”,企业级构建如何破局?
  • 音频像素工坊:5分钟快速上手,体验90年代复古音频处理
  • RexUniNLU在网络安全日志分析中的威胁情报提取
  • 从 CBService 到蓝牙规范:Service、Included Service 与 Apple 的 CoreBluetooth 设计逻辑