单例模式

一、概述

单例模式是结构最简单的设计模式,其核心结构中只包含一个被称为单例类的特殊类。单例模式是一种创建型设计模式,它保证一个类只有一个实例,并且提供一个全局访问点。单例模式用来解决频繁创建与销毁实例对象问题,当我们控制实例创建个数或复用实例,就可以使用单例模式,这样有助于节省系统资源。

定义:确保一个类只有一个实例,并且提供一个全局访问点来访问这个唯一实例。

二、结构

单例模式有三个要点:

  • 某个类只能有一个实例
  • 必须自行创建这个实例
  • 必须自行向整个系统提供这个实例

Singleton单例:在内部实现只生成一个实例,同时它提供一个全局访问点;为了防止外界对其实例化,将其构造函数设计为私有;内部定义一个Singleton类型的静态对象,作为外部共享的唯一实例。

image-20240605221527913

三、实现

  • 普通模式的单例模式
public class Singleton
{
    private static readonly object _lock = new object();
    public static Singleton instance;
    public static Singleton Instance 
    {  
        get 
        { 
            lock(_lock)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }

            return instance;
        } 
    }
}
public class Client
{
    public static void Main(string[] args)
    {
        Singleton s1 = Singleton.Instance;
        Singleton s2 = Singleton.Instance;
        if (s1 == s2) Console.WriteLine("Singleton works, both variables contain the same instance.");
        else Console.WriteLine("Singleton failed, variables contain different instances.");
    }
    // 输出结果为: Singleton works, both variables contain the same instance.
}
  • Unity基于MonoBehavior的单例模式
  public class SingletonMono : MonoBehaviour
  {
      private static SingletonMono instance;
      public static SingletonMono Instance
      {
          get
          {
              return instance;
          }
      }
      protected virtual void Awake()
      {

          if (instance != null)
          {
              instance = this;
              DontDestroyOnLoad(gameObject);
          }
      }
  }

四、优缺点

  • 优点:
    1. 方便好用,单例类提供了对唯一实例的受控访问。
    2. 节约系统资源,由于系统只存在一个对象,所以当一些需要频繁创建和销毁的对象,可以存放与单例类中。
  • 缺点:
    1. 违反了单一职责,单例模式的职责过重,导致过度依赖单例类。
    2. 拓展困难,由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。

五、适用场景

  1. 系统只需要一个实例,且该实例需要长期使用时,可以使用单例模式,可以避免重复创建单例。
  2. 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

​ 了解过很多讨论和博客,大家对单例模式都是保持一个双刃剑的态度,很多人觉得单例模式职责过于重,会有很高的耦合性,我目前认为单例模式利大于弊。单例模式确实不能泛用,但是对于游戏开发来说,一些比较重要的模块比如AudioManager、SceneManager等都可以采用单例模式实现,因为这些都是在游戏中需要全局调用的。