Unity开发通用泛型单例模式

本文详细介绍了在Unity中实现单例模式的多种方法,包括普通C#单例模式、泛型单例模式及针对MonoBehaviour的单例模式,并探讨了线程安全、懒加载等关键概念。

一、普通的C#单例模式(简单)

实现了一个简单的泛型单例模式。这个实现提供了一种方式,可以确保对于任何具有无参数构造函数的类型 T,该类型仅会存在一个实例,并提供一个全局访问点。
简单易用,但缺乏线程安全保护。通过简单的修改,可以实现一个更健壮的单例模式,使其适应多线程环境。在设计模式的使用中要考虑到用例的需求,并根据实际情况进行调整。

public class Singleton<T> where T :new()  {
   
   
	private static T m_Instance;

	public static T Instance {
   
   
		get {
   
   
			if (m_Instance == null) {
   
   
				m_Instance = new T();
			}
			return m_Instance;
		}
	}
}

一个基本的单例模式的实现,它利用了延迟初始化(lazy initialization)来创建实例。尽管这个实现比较简单、有效,但在多线程环境中可能会出现潜在的线程安全问题。在竞争条件的情况下,多个线程可能会同时检测到 m_Instance 为 null,并同时创建多个实例。
改进后的版本
使用lock关键字来确保在多线程场景下的安全性。以下是改进后的代码示例:

public class Singleton<T> where T : new()  
{
   
     
    private static T m_Instance;  
    private static readonly object m_Lock = new object();  

    public static T Instance  
    {
   
     
        get  
        {
   
     
            // 使用双重检查锁定(Double-check locking)以避免不必要的锁定  
            if (m_Instance == null)  
            {
   
     
                lock (m_Lock)  
                {
   
     
                    if (m_Instance == null)  
                    {
   
     
                        m_Instance = new T();  
                    }  
                }  
            }  
            return m_Instance;  
        }  
    }  
}

代码解析:

  1. 锁对象:创建一个私有的静态锁对象 m_Lock,在访问实例时使用它来确保线程互斥。
  2. 双重检查锁定:在获取实例前,先检查 m_Instance 是否为 null。若还未实例化,再进入锁定区块。同时,在锁定区块内再次检查 m_Instance 是否为 null,以避免在锁内创建多个实例的情况。

使用 Lazy 的更优解法
当然,如前面提到的,使用 Lazy 可以进一步简化代码,并确保线程安全,避免手动管理锁:

public class Singleton<T> where T : new()  
{
   
     
    private static readonly Lazy<T> m_Instance = new Lazy<T>(() => new T());  

    public static T Instance => m_Instance.Value;  
}

为什么选择使用 Lazy?
简洁性:代码更简洁,易于维护。
线程安全:Lazy 内置了线程安全的实现,避免了显式的锁管理。
延迟初始化:实例只有在第一次访问时才会被创建,节省了资源。
总结
如果您需要一个简单的单例实现,并且考虑到线程安全,以上的双重检查锁定方法是合适的。如果您对简便性、可读性和线程安全的保证有更高的要求,推荐使用 Lazy。在大多数情况下,Lazy 是实现单例模式的最佳实践。
为了进一步优化单例模式的实现,我们可以考虑使用静态初始化器或者懒汉式与双重检查锁定的结合,但通常静态初始化器是实现单例模式的最佳方式,因为它既简单又高效,并且由CLR(公共语言运行时)保证了线程安全。

public class Singleton<T> where T : new()  
{
   
     
    // 静态初始化器在类被加载时立即初始化,保证线程安全  
    private static readonly T m_Instance = new T();  
  
    // 提供一个公共的静态属性来访问实例  
    public static T Instance  
    {
   
     
        get {
   
    return m_Instance; }  
    }  
  
    // 私有构造函数,防止外部实例化  
    private Singleton() {
   
   }  
}

二、普通的C#单例模式(多线程安全机制)

一个典型的泛型单例模式(Singleton Pattern)的实现,它确保某个类只会有一个实例,并提供一个全局访问点来获得该实例。这个泛型单例模式的实现是一个有效且线程安全的单例设计,它遵循了 C# 的最佳实践。此模式的主要优点是能够抽象出单例的逻辑,使得任何希望成为单例的类都可以通过简单的继承来实现。
一个基本的单例模式实现,并且包含了多线程安全机制。虽然这个实现已经很接近理想,但在某些方面还有进一步优化的空间。此外,类的设计允许您创建任意类型的单例(只要这些类型符合约束条件)

public abstract class Singleton<T> where T : class, new()
{
   
   
    private static T instance = null;
 
    // 多线程安全机制
    private static readonly object locker = new object();
 
    public static T Instance
    {
   
   
        get
        {
   
   
            lock (locker)
            {
   
   
                if (instance == null)
                    instance = new T();
                return instance;
            }
        }
    }
}

改进建议
虽然您的实现已经很不错,但使用双重检查锁定(Double-check locking)是不必要的加锁操作,可以提升性能。以下是改进后的代码示例:

public abstract class Singleton<T> where T : class, new()  
{
   
     
    private static T _instance = null;  
    private static readonly object _locker = new object();  
    
    public static T Instance  
    {
   
     
        get  
        {
   
     
            if (_instance == null) // 首次检查  
            {
   
     
                lock (_locker) // 锁定  
                {
   
     
                    // 再次检查  
                    if (_instance == null)  
                    {
   
     
                        _instance = new T(); // 实例化  
                    }  
                }  
            }  
            return _instance;  
        }  
    }  
}

如果你想避免锁定和提高标准化程度,可以考虑使用 Lazy 实现更简洁的单例模式:

using System;  

public class Singleton<T> where T : class, new()  
{
   
     
    private static readonly Lazy<T> instance = new Lazy<T
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值