设计模式

观察者模式:

点击查看代码
// 采用观察者模式实现,降低系统间耦合度
public static class EventHandle
{
    // 事件定义(被观察者)
    public static event Action<InventoryLocation, List<InventoryItem>> UpdateInventoryUI;
    
    // 触发通知方法
    public static void CallUpdateInventoryUI(InventoryLocation location, List<InventoryItem> list)
    {
        // ?. 操作符确保即使没有订阅者也不会引发异常
        UpdateInventoryUI?.Invoke(location, list);
    }
    
    // 另一个事件示例
    public static event Action<int, Vector3> InstantiateItemInScene;
    
    public static void CallInstantiateItemInScene(int ID, Vector3 pos)
    {
        InstantiateItemInScene?.Invoke(ID, pos);
    }
}
// 在InventoryUI.cs中订阅事件
private void OnEnable()
{
    EventHandle.UpdateInventoryUI += OnUpdateInventoryUI; // 注册库存更新事件
}

private void OnDisable()
{
    EventHandle.UpdateInventoryUI -= OnUpdateInventoryUI; // 取消注册库存更新事件
}

// 事件处理方法
private void OnUpdateInventoryUI(InventoryLocation location, List<InventoryItem> list)
{
    // 处理UI更新逻辑
}
// 在InventoryManager.cs中触发事件
EventHandle.CallUpdateInventoryUI(InventoryLocation.Player, playerBag.itemList);
观察者模式的最大优势是实现了模块间的松耦合,比如在项目中,ItemManager和InventoryUI通过EventHandle通信,而不需要直接引用对方,这使得代码更加模块化和可维护。
单例模式:
点击查看代码
// 通用单例模式基类,确保一个类只有一个实例
// T: 继承该类的具体类型
public class Singleton<T> : MonoBehaviour
    where T : Singleton<T>
{
    // 静态实例,用于全局访问
    private static T instance;

    // 公共访问器,获取单例实例
    public static T Instance
    {
        get => instance;
    }

    // 在对象初始化时确保只有一个实例存在
    protected virtual void Awake()
    {
        // 如果已经存在实例,销毁当前对象
        if (instance != null)
            Destroy(gameObject);
        else
            // 否则将当前对象设为实例
            instance = (T)this;
    }

    // 当对象被销毁时清理实例引用
    protected virtual void OnDestroy()
    {
        // 在销毁时清理该对象相关的所有 tween
        DOTween.Kill(this);

        if (instance == this)
            instance = null;
    }
}
/// <summary>
/// 库存管理系统(单例模式)
/// 功能:
/// 1. 管理游戏内所有物品数据
/// 2. 提供物品信息的查询接口
/// 3. 处理物品的添加/移除逻辑
/// </summary>
public class InventoryManager : Singleton<InventoryManager>
{
    [Header("物品数据")]
    public ItemDataList_SO ItemDataList_SO;

    [Header("背包数据")]
    public InventoryBag_SO playerBag;
    
    // 方法实现...
}
单例模式的使用示例
在代码中,您可以通过Instance静态属性访问单例实例,例如:
// 在SlotUI.cs中
InventoryManager.Instance.SwapItem(slotIndex, targetIndex);

// 在其他地方可以获取物品信息
var itemDetails = InventoryManager.Instance.GetItemDetails(itemID);
单例模式在游戏开发中的优势:
全局访问点:提供一个全局唯一的访问点,无需传递引用
状态共享:确保系统中只有一个状态实例,避免数据不一致
延迟初始化:资源可以在首次使用时才被创建
减少内存占用:避免创建多个相同功能的对象
在您的项目中,单例模式主要应用于需要全局访问的管理类,如库存管理系统,这是Unity游戏开发中的常见做法,特别适合那些在整个游戏生命周期中需要维护状态的系统。

Unity 的 SceneManager 类提供了方法来加载和卸载场景。可以使用 SceneManager.LoadScene 方法来切换场景,并在需要时管理对象的生命周期。

点击查看代码
public class SceneLoader : MonoBehaviour
{
    public void LoadNewScene(string sceneName)
    {
        SceneManager.LoadScene(sceneName);
    }
}

ScriptableObject 是一种轻量级的对象,可以在多个场景中共享数据。它们不会在场景切换时被销毁,适合存储游戏设置、配置或状态。

点击查看代码
[CreateAssetMenu(fileName = "GameSettings", menuName = "ScriptableObjects/GameSettings")]
public class GameSettings : ScriptableObject
{
    public int playerHealth;
    public float gameSpeed;
}

使用事件系统可以在不同的对象之间传递信息,而不需要直接引用。这样可以减少对象之间的耦合,便于管理对象的生命周期。

点击查看代码
public class EventManager : MonoBehaviour
{
    public delegate void GameEvent();
    public static event GameEvent OnGameStart;

    public void StartGame()
    {
        OnGameStart?.Invoke();
    }
}

对象池是一种设计模式,用于管理对象的创建和销毁,特别是在需要频繁创建和销毁对象的情况下(如子弹、敌人等)。通过重用对象,可以提高性能。

点击查看代码
public class ObjectPool : MonoBehaviour
{
    public GameObject prefab;
    private Queue<GameObject> pool = new Queue<GameObject>();

    public GameObject GetObject()
    {
        if (pool.Count > 0)
        {
            return pool.Dequeue();
        }
        else
        {
            return Instantiate(prefab);
        }
    }

    public void ReturnObject(GameObject obj)
    {
        obj.SetActive(false);
        pool.Enqueue(obj);
    }
}

使用状态模式可以管理游戏对象的不同状态,特别是在需要在不同状态之间切换时(如角色的行走、跳跃、攻击状态)。

点击查看代码
public interface IState
{
    void Enter();
    void Execute();
    void Exit();
}

public class WalkingState : IState
{
    public void Enter() { /* 进入行走状态 */ }
    public void Execute() { /* 执行行走逻辑 */ }
    public void Exit() { /* 退出行走状态 */ }
}
单例模式和线程同步
点击查看代码
namespace ZJHServer
{
    // 定义可执行的无参数、无返回值的委托类型
    // 用于向Execute方法传递要执行的代码块
    public delegate void ExecuteDelegate();

    // 线程安全的单例执行器
    // 用于确保在多线程环境下,指定的代码块在任意时刻只被一个线程执行
    // 结合了单例模式和线程同步机制,防止并发操作引起的数据竞争
    public class SingleExecute
    {
        private static object ob = new object(); // 用于单例模式的线程锁对象
        private static SingleExecute instance = null; // 单例实例,使用懒加载模式

        // 单例访问器,使用双锁检测模式确保线程安全
        // 所有线程将共享同一个SingleExecute实例
        public static SingleExecute Instance
        {
            get
            {
                lock (ob) // 外部锁:确保线程安全
                {
                    if (instance == null)
                    {
                        instance = new SingleExecute();
                    }
                    return instance;
                }
            }
        }

        private object objLock = new object(); // 用于Execute方法的互斥锁
        private Mutex mutex = null; // 互斥量对象,提供更强的线程同步机制

        // 构造函数,初始化互斥量
        // 私有构造函数确保只能通过Instance属性创建实例
        public SingleExecute()
        {
            mutex = new Mutex(); // 创建未命名的互斥量
        }

        // 线程安全地执行传入的委托方法
        // 使用两层锁机制确保任意时刻只有一个线程在执行委托
        //
        // 应用场景:
        // 1. 数据库操作等共享资源访问
        // 2. 需要顺序执行且不允许并行的业务逻辑
        // 3. 防止多线程导致的数据不一致问题
        //
        // 参数 executeDelegate: 要执行的委托方法
        public void Execute(ExecuteDelegate executeDelegate)
        {
            lock (objLock) // 第一层锁:确保单线程进入
            {
                try
                {
                    mutex.WaitOne(); // 第二层锁:等待互斥量
                    executeDelegate(); // 执行委托方法(临界区代码)
                }
                finally
                {
                    mutex.ReleaseMutex(); // 确保释放互斥量,防止死锁
                }
            }
        }
    }
}

posted @ 2024-10-14 19:33  doudouqie66  阅读(57)  评论(0)    收藏  举报