ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

设计模式之单例模式

2026/8/16 10:25:14 拓冰建站 浏览量
设计模式之单例模式

1. 什么是单例模式
单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。

2. 单例模式的类型
单例模式有两种类型:
懒汉式:在真正需要使用对象时才去创建该单例类对象
懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象。,否则则先执行实例化操作。

public class Singleton 
{private static Singleton singleton;private Singleton(){}public static Singleton getInstance() {if (singleton == null) {singleton = new Singleton();}return singleton;}}

这个方法其实是存在问题的,试想一下,如果两个线程同时判断singleton为空,那么它们都会去实例化一个Singleton对象,这就不符合单例模式只有一个实例对象的要求。所以在实例化对象时加锁。

public static Singleton getInstance() 
{//线程A和线程B同时看到singleton = null,如果不为null,则直接返回singletonif (singleton == null){  // 线程A或线程B获得该锁进行初始化synchronized(Singleton.class){//其中一个线程进入该分支,另外一个线程则不会进入该分支if (singleton == null){singleton = new Singleton();}}}return singleton;
}

饿汉式:在类加载时已经创建好该单例对象,等待被程序使用
饿汉式在类加载时已经创建好该对象,在程序调用时直接返回该单例对象即可,即我们在编码时就已经指明了要马上创建这个对象,不需要等到被调用时再去创建。

public class Singleton{private static final Singleton singleton = new Singleton();private Singleton(){}public static Singleton getInstance() {return singleton;}
}

注意上面的代码在第3行已经实例化好了一个Singleton对象在内存中,不会有多个Singleton对象实例存在类在加载时会在堆内存中创建一个Singleton对象,当类被卸载时,Singleton对象也随之消亡了。

Unity中的单例模式
Unity中各种Manager常用懒汉式单例模式设计。一般会创建一个泛型单利模式的BaseManager,让其他管理类继承BaseManager实现单例模式Manager。
不继承MonoBehaviour的单例模式

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//泛型单例模式基类
public class BaseManager<T> where T:class,new() //泛型约束,让子类必须实现公共无参构造函数
{private static T instance;public static T Instance{get{if(instance==null){instance = new T();}return instance;}}
}//创建UIManager继承BaseManager
public class UIManager:BaseManager<UIManager> 
{public UIManager(){}
}

不继承MonoBehaviour的BaseManager需要在子类中自定义公共类型的无参构造函数,不需要挂载到对象上。可以在其他脚本中通过new实例化出来(缺点,违反了单例模式)。为了解决这个问题,使用反射来优化,让构造函数设置为私有,不能再外部访问。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class BaseManager<T> where T:class
{private static T instance;public static T Instance{get{if(instance==null){//获取到T类的信息Type type = typeof(T);//获取到T类的非公共构造函数(成员构造函数,非公共构造函数,绑定对象,参数类型,参数列表)ConstructorInfo info = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null,Type.EmptyTypes,null);if(info!=null){//调用构造函数instance = info.Invoke(null) as T;}else{Debug.Log("没有无参构造函数");}}return instance;}}
}//创建UIManager继承BaseManager
public class UIManager:BaseManager<UIManager> 
{//子类需要实现私有构造函数private UIManager(){}
}

继承MonoBehaviour的单例模式

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//自动挂载脚本
public class BaseManager<T> : MonoBehaviour where T:MonoBehaviour//泛型约束,让子类必须继承MonoBehaviour
{private static T instance;public static T Instance{get{if(instance==null){//创建一个对象GameObject obj = new GameObject();//将该脚本挂载到对象上instance = obj.AddComponent<T>();//为对象取名为当前类的名字obj.name = typeof(T).ToString();//跨场景不销毁对象DontDestroyOnLoad(obj);}return instance;}}
}//创建UIManager继承BaseManager
public class UIManager:BaseManager<UIManager> 
{void Start(){}void Update(){}
}

继承MonoBehaviour的BaseManager子类不需要声明无参构造函数,需要挂载到对象上,但不能被实例化。可以执行Start,Update等生命周期函数和协同程序。

总结
单例模式是一种常见的设计模式,它让一个类只有一个实例,并提供一个全局访问点来获取该实例。单例模式适用于需要全局唯一实例的场景,如日志记录器、配置管理类等。在使用单例模式时,需要注意线程安全问题,以及避免出现多次实例化问题。