设计模式——单例模式

前言:在Unity中,单例模式是一种常用的软件设计模式,它确保一个类只有一个实例,并提供一个全局访问点。比如我们常用的游戏管理器GameManager,我们只希望游戏中只存在一个,这个时候就可以使用单例模式,来确保只有一个游戏管理器。

单例模式可以分为懒汉式和饿汉式。

  1. 其中懒汉式顾名思义,就是很懒,只有真正用到它的时候,才会实例化出来。一般的写法大致可以分为线程不安全的经典写法,和线程安全的写法。我这里只介绍线程安全的方法,所谓线程的安全的写法,就是避免在多线程环境下创建多个实例出来,多个实例就破坏了单例原则。
    下面是单例代码
using UnityEngine;
using System;


    /// 
    /// 泛型单例基类,支持继承并实现单例模式
    /// 
    /// 继承自 MonoBehaviour 的类
    public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
    {
        // 定义一个静态的 Lazy 对象,用于线程安全地初始化单例
        private static Lazy<T> _instanceLazy = new Lazy<T>(() =>
        {
            // 尝试在场景中查找已存在的 T 类型的实例
            T instance = FindObjectOfType<T>();
            if (instance == null)
            {
                // 如果找不到实例,创建一个新的 GameObject,并添加 T 类型的组件
                GameObject singletonObject = new GameObject(typeof(T).Name + "_Singleton");
                instance = singletonObject.AddComponent<T>();
                // 确保这个 GameObject 在场景切换时不会被销毁
                DontDestroyOnLoad(singletonObject);
            }
            return instance;
        });

        // 获取单例实例
        private static T _instance => _instanceLazy.Value;
        // 标记单例是否已初始化
        private static bool _isInitialized = false;

        // 提供对单例实例的访问
        public static T Instance
        {
            get
            {
                if (!_isInitialized)
                {
                    // 如果单例尚未初始化,强制初始化
                    _instanceLazy.Value;
                    _isInitialized = true;
                }
                return _instance;
            }
        }

        // 在对象被初始化时调用
        protected virtual void Awake()
        {
            if (_instance == null)
            {
                // 如果单例实例为空,重新初始化
                _instanceLazy = new Lazy<T>(() =>
                {
                    GameObject singletonObject = new GameObject(typeof(T).Name + "_Singleton");
                    T instance = singletonObject.AddComponent<T>();
                    DontDestroyOnLoad(singletonObject);
                    return instance;
                });
                _instanceLazy.Value;
                _isInitialized = true;
            }
            else if (_instance != this)
            {
                // 如果当前对象不是单例实例,销毁它
                Destroy(gameObject);
            }
        }

        // 在对象被销毁时调用
        protected virtual void OnDestroy()
        {
            if (_instance == this)
            {
                // 如果当前对象是单例实例,重置单例引用
                _instanceLazy = null;
                _isInitialized = false;
            }
        }
    }

使用示例
假设我们有一个游戏管理器类,我们希望它在整个游戏中只有一个实例

using UnityEngine;


    public class GameManager : SingletonMono<GameManager>
    {
        // 游戏管理器的具体逻辑
        private int score = 0;
        private int lives = 3;

        public void AddScore(int points)
        {
            score += points;
            Debug.Log("Score: " + score);
        }

        public void LoseLife()
        {
            lives--;
            Debug.Log("Lives: " + lives);
        }
    }

在其他脚本中,你可以通过以下方式访问 GameManager 的实例:

using UnityEngine;


public class PlayerController : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // 访问 GameManager 的单例实例并调用方法
            GameManager.Instance.AddScore(10);
        }

        if (Input.GetKeyDown(KeyCode.Escape))
        {
            GameManager.Instance.LoseLife();
        }
    }
}
  1. 饿汉式单例在类加载时就初始化实例,确保实例在程序启动时就可用。它适用于需要在程序启动时就初始化的场景,并且在单线程环境下性能较高。然而,它不支持延迟初始化,因此在资源有限或对象创建成本较高的场景中可能不太适用。
    饿汉式单例实现
using UnityEngine;

public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    // 静态实例在类加载时就初始化
    private static T _instance;

    // 在类加载时初始化实例
    static SingletonMono()
    {
        GameObject singletonObject = new GameObject(typeof(T).Name + "_Singleton");
        _instance = singletonObject.AddComponent<T>();
        DontDestroyOnLoad(singletonObject);
    }

    // 提供对单例实例的访问
    public static T Instance => _instance;

    // 在对象被初始化时调用
    protected virtual void Awake()
    {
        if (_instance != this)
        {
            // 如果当前对象不是单例实例,销毁它
            Destroy(gameObject);
        }
    }

    // 在对象被销毁时调用
    protected virtual void OnDestroy()
    {
        // 饿汉式单例通常不需要重置引用,因为实例在类加载时就已创建
    }
}

举个栗子

using UnityEngine;

public class GameManager : SingletonMono<GameManager>
{
    private int score = 0;
    private int lives = 3;

    public void AddScore(int points)
    {
        score += points;
        Debug.Log("Score: " + score);
    }

    public void LoseLife()
    {
        lives--;
        Debug.Log("Lives: " + lives);
    }
}

使用单例实例

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GameManager.Instance.AddScore(10);
        }

        if (Input.GetKeyDown(KeyCode.Escape))
        {
            GameManager.Instance.LoseLife();
        }
    }
}

你可能感兴趣的:(游戏设计模式,设计模式,单例模式,unity,笔记)