当前位置:   article > 正文

看完就懂Unity设计模式那些事(单例,观察者,工厂)_unity不能不知道的那些事

unity不能不知道的那些事

1.单例模式

保证一个类只有一个实例,且具有全局访问点,一般用作管理器,下面是用静态变量实现的单例

  1. /// <summary>
  2. /// 单例基类
  3. /// </summary>
  4. //<summary>:这个标签是用于代码文档生成工具的,通常在编写代码时会用来描述代码的功能、用途等。在这里,它说明下面的代码是一个单例基类。
  5. public class Singleton<T> where T : new()
  6. {
  7. static T instance;
  8. public static T Instance
  9. {
  10. get
  11. {
  12. if (instance == null)
  13. {
  14. instance = new T();
  15. }
  16. return instance;
  17. }
  18. }
  19. }

解释代码:

  1. public class Singleton<T> where T : new():这是一个泛型类定义,命名为 Singleton,其中 T 是一个类型参数。where T : new() 这部分表示 T 必须有一个无参数的公共构造函数,因为在后面的代码中会使用 new T() 来创建 T 类型的实例。泛型就是不知道具体是什么类型,就用T占位字符先表示,所以之后的代码逻辑,不管什么类型的参数,都执行相同的代码逻辑

  2. static T instance;:这是一个静态字段,用来保存单例实例。因为它是静态的,所以所有使用该类的实例将共享这个字段。

  3. public static T Instance { get { ... } }:这是一个静态属性,用来获取单例实例。通过这个属性可以访问单例对象。

  4. get:这是属性的访问器,用来获取属性值。在这个访问器中,如果实例还没有被创建,它会通过 new T() 来创建一个新的实例,并将其赋值给 instance,然后返回该实例。如果实例已经存在,它直接返回已有的实例。

这样设计的好处是,无论使用何种类型,只需要继承这个泛型基类,就可以轻松地创建对应类型的单例。

其他类转换为单例,ShopMgr是商店管理器,继承Singleton就转换为单例

  1. class ShopMgr : Singleton<ShopMgr>
  2. {
  3. //具体逻辑
  4. }

2.观察者模式

观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,主要用于解耦代码

这里使用一个简单的事件管理器来演示逻辑

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class EventManager : Singleton<EventManager>
  5. {
  6. public delegate void EventCallBack(object param);// 事件回调函数
  7. // 事件字典
  8. Dictionary<int, List<EventCallBack>> mDictEvent = new Dictionary<int, List<EventCallBack>>();
  9. /// <summary>
  10. /// 添加事件监听
  11. /// </summary>
  12. public void AddEvent(int eventId, EventCallBack callBack)
  13. {
  14. if(!mDictEvent.ContainsKey(eventId))
  15. {
  16. mDictEvent.Add(eventId,new List<EventCallBack>());
  17. }
  18. if(!mDictEvent[eventId].Contains(callBack))
  19. {
  20. mDictEvent[eventId].Add(callBack);
  21. }
  22. else
  23. {
  24. Debug.LogWarning("Repeat Add Event CallBack,EventId = " + eventId + ",CallBack = " + callBack.ToString());
  25. }
  26. }
  27. /// <summary>
  28. /// 删除事件监听
  29. /// </summary>
  30. public void DelEvent(int eventId, EventCallBack callBack)
  31. {
  32. if(!mDictEvent.ContainsKey(eventId))
  33. {
  34. return;
  35. }
  36. if(!mDictEvent[eventId].Contains(callBack))
  37. {
  38. return;
  39. }
  40. mDictEvent[eventId].Remove(callBack);
  41. // 如果回调都被移除了 那么key也从字典移除
  42. if (mDictEvent[eventId].Count < 1)
  43. {
  44. mDictEvent.Remove(eventId);
  45. }
  46. }
  47. /// <summary>
  48. /// 通知事件
  49. /// </summary>
  50. public void NotifyEvent(int eventId,object param)
  51. {
  52. if(mDictEvent.ContainsKey(eventId))
  53. {
  54. foreach(var callback in mDictEvent[eventId])
  55. {
  56. callback(param);
  57. }
  58. }
  59. }
  60. }

解释代码:

这段代码定义了一个名为 EventManager 的类,它继承了之前我们提到的泛型单例模式的基类。让我解释每一部分的含义:

  1. using System.Collections;using System.Collections.Generic;:这两行是命名空间的引用,用于在代码中使用集合类和泛型集合类。

  2. using UnityEngine;:这行引用了 Unity 引擎的命名空间,使得代码可以使用 Unity 的 API。

  3. public class EventManager : Singleton<EventManager>:这是一个类定义,它继承了之前定义的 Singleton 泛型基类,并指定了泛型参数为 EventManager 自身。这意味着 EventManager 类将作为单例使用。

  4. public delegate void EventCallBack(object param);:这行定义了一个委托类型 EventCallBack,它表示一个事件回调函数,参数为 object 类型。

  5. Dictionary<int, List<EventCallBack>> mDictEvent = new Dictionary<int, List<EventCallBack>>();:这是一个字典类型的字段,用于存储事件和对应的事件回调函数列表。键为整数类型(事件ID),值为事件回调函数列表。这个字典用于管理事件和事件回调函数之间的关系。

  6. public void AddEvent(int eventId, EventCallBack callBack):这是一个公共方法,用于添加事件监听。它接受两个参数,一个是事件ID,另一个是事件回调函数。它首先检查是否已存在该事件ID对应的回调函数列表,如果不存在,则创建一个新的列表,并将回调函数添加到列表中。如果已存在列表,则只需将回调函数添加到列表中。

  7. public void DelEvent(int eventId, EventCallBack callBack):这是一个公共方法,用于删除事件监听。它接受两个参数,一个是事件ID,另一个是要删除的事件回调函数。它首先检查是否存在该事件ID对应的回调函数列表,如果不存在,则直接返回。如果存在列表,则检查回调函数是否在列表中,如果在,则将其从列表中移除。如果移除后列表为空,则将事件ID从字典中移除。

  8. public void NotifyEvent(int eventId, object param):这是一个公共方法,用于通知事件。它接受两个参数,一个是事件ID,另一个是要传递给事件回调函数的参数。它首先检查是否存在该事件ID对应的回调函数列表,如果存在,则遍历列表,并依次调用每个回调函数,并将参数传递给它们。

通过这段代码,你可以方便地在 Unity 中管理事件和事件回调函数,实现事件的订阅、发布和取消订阅功能。

定义商店刷新事件的id:

  1. public class EventId
  2. {
  3. public static int OnShopDataChange = 1; //商店数据变化时触发
  4. public static int OnGoldChange = 2; //金币变化时触发
  5. }

以UI界面的刷新为例,打开商店UI时监听商店数据变化,关闭时移除监听

  1. public class ShopUI
  2. {
  3. private void RegisterEvent()//打开商店
  4. {
  5. EventManager.Instance.AddEvent(EventId.OnShopDataChange, OnDataChange);
  6. //添加:商店数据变化时,商店UI的刷新事件
  7. EventManager.Instance.AddEvent(EventId.OnGoldChange, OnDataChange);
  8. }
  9. private void UnRegisterEvent()//关闭商店
  10. {
  11. EventManager.Instance.DelEvent(EventId.OnShopDataChange, OnDataChange);
  12. EventManager.Instance.DelEvent(EventId.OnGoldChange, OnDataChange);
  13. }
  14. private void OnDataChange(object param)//只要商店数据变化就会触发
  15. {
  16. //刷新UI的具体逻辑
  17. }
  18. }

当商店的数据变化或者金币变化时,就会触发对应的事件,刷新商店的UI

  1. class ShopMgr : Singleton<ShopMgr>
  2. {
  3. private void OnDataChange()
  4. {
  5. EventManager.Instance.NotifyEvent(EventId.OnShopDataChange, null);
  6. }
  7. }
  8. class ItemMgr : Singleton<ItemMgr>
  9. {
  10. private void OnDataChange()
  11. {
  12. EventManager.Instance.NotifyEvent(EventId.OnGoldChange, null);
  13. }
  14. }

3.工厂模式

简单工厂模式

通常用于创建单一的对象类型

定义道具基类及其子类

  1. using UnityEngine;
  2. public abstract class ItemBase
  3. {
  4. protected string name;
  5. public virtual void Use()
  6. {
  7. Debug.Log("使用了" + name);
  8. }
  9. }
  10. public class HealthPotion : ItemBase
  11. {
  12. public HealthPotion()
  13. {
  14. name = "生命药水";
  15. }
  16. public override void Use()
  17. {
  18. base.Use();
  19. //具体的使用逻辑
  20. Debug.Log("恢复了100点生命");
  21. }
  22. }
  23. public class ManaPotion : ItemBase
  24. {
  25. public ManaPotion()
  26. {
  27. name = "魔法药水";
  28. }
  29. public override void Use()
  30. {
  31. base.Use();
  32. //具体的使用逻辑
  33. Debug.Log("恢复了100点魔法");
  34. }
  35. }
  36. public class SpeedBoost : ItemBase
  37. {
  38. public SpeedBoost()
  39. {
  40. name = "加速药剂";
  41. }
  42. public override void Use()
  43. {
  44. base.Use();
  45. //具体的使用逻辑
  46. Debug.Log("增加了移动速度");
  47. }
  48. }

解释代码:

这段代码定义了一个简单的物品系统,其中包括一个抽象基类 ItemBase 和三个具体的物品类 HealthPotionManaPotionSpeedBoost。让我逐个解释每个部分的含义:

  1. using UnityEngine;:这是 Unity 引擎的命名空间引用,使得代码可以使用 Unity 的 API。

  2. public abstract class ItemBase:这是一个抽象基类的定义,命名为 ItemBase。抽象类是不能直接实例化的,它定义了一个通用的物品模板,其中包含了物品的基本属性和行为。

  3. protected string name;:这是一个受保护的字符串字段,用于存储物品的名称。由于它是受保护的,所以只能在 ItemBase 类及其派生类中访问。

  4. public virtual void Use():这是一个公共的虚拟方法,用于执行物品的使用操作。在基类中,这个方法的实现只是简单地输出一个使用信息,其中包含物品的名称。因为它被声明为虚拟方法,所以它可以在派生类中被重写。

  5. public class HealthPotion : ItemBase:这是一个具体的物品类 HealthPotion 的定义,它继承自 ItemBase 基类。它代表了一种生命药水物品。

  6. public HealthPotion():这是 HealthPotion 类的构造函数,它初始化了物品的名称为 "生命药水"。

  7. public override void Use():这是对基类中的虚拟方法 Use() 的重写。在 HealthPotion 类中,除了调用基类方法输出使用信息外,还增加了具体的使用逻辑,即恢复了100点生命。

  8. public class ManaPotion : ItemBasepublic class SpeedBoost : ItemBase:这两个类与 HealthPotion 类的结构和功能类似,分别代表了魔法药水和加速药剂物品。它们也都继承自 ItemBase 基类,并在构造函数中初始化了物品的名称,并重写了 Use() 方法,实现了各自的使用逻辑。

通过这样的设计,你可以轻松地扩展物品系统,添加新的物品类,并根据需要定义不同的使用行为。

定义创建道具的工厂

  1. public class ItemFactory
  2. {
  3. public static ItemBase CreateItem(string itemName)
  4. {
  5. ItemBase item = null;
  6. switch (itemName)
  7. {
  8. case "Health_Potion":
  9. item = new HealthPotion();
  10. break;
  11. case "Mana_Potion":
  12. item = new ManaPotion();
  13. break;
  14. case "Speed_Boost":
  15. item = new SpeedBoost();
  16. break;
  17. }
  18. return item;
  19. }
  20. }

游戏中通过ItemFactory创建并使用道具,只能创建ItemBase类型的对象

  1. //创建并使用生命药水
  2. ItemBase healthPotion = ItemFactory.CreateItem("Health_Potion");
  3. healthPotion.Use();
  4. //创建并使用加速药剂
  5. ItemBase speedBoost = ItemFactory.CreateItem("Speed_Boost");
  6. speedBoost.Use();

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/865641
推荐阅读
相关标签
  

闽ICP备14008679号