2.单例模块

2.单例模块


2.1 知识点

单例模块的作用

减少单例模式重复代码的书写

单例的基本要素

静态实例

私有构造函数

公共访问属性

C#中的泛型单例基类

定义泛型基类:

使用 public class BaseSingletonInCSharp<T> 定义一个泛型基类,其中 T 是泛型参数。
添加泛型约束 where T : class, new(),确保 T 是引用类型(class)并且具有无参数构造函数(new())。

私有静态字段:

声明一个私有静态字段 private static T instance; 用于存储单例实例。
声明一个私有静态字段 private static readonly object LockObject = new object(); 用于线程同步。

公共静态属性 Instance:

声明一个公共静态属性 public static T Instance 用于获取单例实例。
在 get 访问器中实现单例模式的逻辑。
如果 instance 为 null,则进入锁定区域以确保线程安全。
再次检查 instance 是否为 null,以防多个线程同时通过第一个检查。
如果 instance 仍为 null,就在锁定区域内创建一个新的实例并赋值给 instance。
最后,返回单例实例。

受保护的构造函数:

声明一个受保护的构造函数 protected BaseSingletonInCSharp(),表示该构造函数只能在类内部或派生类中访问。
可以在构造函数中添加初始化代码,但通常不需要,因为实例化是延迟的。

MonoBehaviour中的泛型单例基类

引入Unity引擎的命名空间:

使用 using UnityEngine; 引入Unity引擎的命名空间,以便在代码中使用Unity的类和功能。

声明泛型类 BaseSingletonInMonoBehaviour

使用 public class BaseSingletonInMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour 声明一个泛型类 BaseSingletonInMonoBehaviour,它继承自MonoBehaviour。
泛型参数 T 必须是MonoBehaviour的派生类。

私有静态字段:

声明一个私有静态字段 private static T instance; 用于存储单例实例。

公共静态属性 Instance:

声明一个公共静态属性 public static T Instance 用于获取单例实例。
在 get 访问器中实现单例模式的逻辑。
如果 instance 为 null,则尝试在场景中查找具有类型 T 的对象。
如果在场景中找不到该类型的对象,就创建一个新的空游戏对象,向其添加一个类型为 T 的组件,并将其赋值给 instance。
设置游戏对象的名称为类型 T 的名称,并防止在场景切换时销毁这个游戏对象。
最后,返回单例实例。

Awake 虚方法:

Awake 虚方法在对象实例被创建时调用。
如果单例实例尚未创建(即 instance 为 null),则将当前对象实例赋值给 instance。
同样,防止在场景切换时销毁当前对象。
如果单例实例已存在,则销毁当前对象,确保只有一个单例实例存在。

单例测试

测试代码

TestCSharpSingleton.Instance.ShowCSharpInfo();
TestMonoBehaviourSingleton.Instance.ShowMonoBehaviourInfo();

测试结果


2.2 知识点代码

BaseSingletonInCSharp

// 定义一个泛型基类 BaseSingletonInCSharp,要求泛型类型 T 必须是引用类型(class)并且具有无参数构造函数(new())
public class BaseSingletonInCSharp<T> where T : class, new()
{
    // 用于存储单例实例的私有静态字段
    private static T instance;

    // 用于线程同步的锁对象
    private static readonly object LockObject = new object();

    // 公共静态属性,用于获取单例实例
    public static T Instance
    {
        get
        {
            // 如果实例尚未创建
            if (instance == null)
            {
                // 使用锁确保线程安全
                lock (LockObject)
                {
                    // 再次检查实例是否为空,因为多个线程可能同时通过第一个检查
                    if (instance == null)
                    {
                        // 如果为空,创建一个新的实例并赋值给 instance
                        instance = new T();
                    }
                }
            }
            // 返回单例实例
            return instance;
        }
    }

    // 受保护的构造函数,只能在类内部或派生类中访问
    protected BaseSingletonInCSharp()
    {
        // 这里可以添加初始化代码,但通常不需要,因为实例化是延迟的
    }
}

BaseSingletonInMonoBehaviour

// 引入Unity引擎的命名空间
using UnityEngine;

// 声明一个泛型类 BaseSingletonInMonoBehaviour<T>
// 这个类继承自MonoBehaviour,泛型参数 T 必须是MonoBehaviour的派生类
public class BaseSingletonInMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
    // 静态字段用于存储单例实例
    private static T instance;

    // 公共静态属性,用于获取单例实例
    public static T Instance
    {
        get
        {
            // 如果实例尚未创建
            if (instance == null)
            {
                // 尝试在场景中查找具有类型 T 的对象
                instance = FindObjectOfType<T>();

                // 如果在场景中找不到该类型的对象
                if (instance == null)
                {
                    // 创建一个新的空游戏对象
                    GameObject gameObject = new GameObject();

                    // 向新创建的游戏对象添加一个类型为 T 的组件,并将其赋值给 instance
                    instance = gameObject.AddComponent<T>();

                    // 设置游戏对象的名称为类型 T 的名称
                    gameObject.name = typeof(T).ToString();

                    // 不要在场景切换时销毁这个游戏对象
                    DontDestroyOnLoad(gameObject);
                }
            }

            // 返回单例实例
            return instance;
        }
    }

    // Awake 方法在对象实例被创建时调用
    protected virtual void Awake()
    {
        // 如果单例实例尚未创建
        if (instance == null)
        {
            // 将当前对象实例赋值给 instance
            instance = this as T;

            // 不要在场景切换时销毁该对象
            DontDestroyOnLoad(this.gameObject);
        }
        else
        {
            // 如果单例实例已存在,则销毁当前对象
            Destroy(this);
        }
    }
}

TestCSharpSingleton

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestCSharpSingleton : BaseSingletonInCSharp<TestCSharpSingleton>
{
    public void ShowCSharpInfo()
    {
        Debug.Log($"我是CSharp单例中的{this.GetType().Name}!");
    }
}

TestMonoBehaviourSingleton

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestMonoBehaviourSingleton : BaseSingletonInMonoBehaviour<TestMonoBehaviourSingleton>
{
    public void ShowMonoBehaviourInfo()
    {
        Debug.Log($"我是MonoBehaviour单例中的{this.GetType().Name}!");
    }
}

Lesson02_单例模块

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson02_单例模块 : MonoBehaviour
{
    void Start()
    {
        TestCSharpSingleton.Instance.ShowCSharpInfo();
        TestMonoBehaviourSingleton.Instance.ShowMonoBehaviourInfo();
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏