2.创建型模式-单例模式
2.1 基础知识
学习难度:1
使用频率:4
总分:9
定义
单例模式(Singleton)保证一个类仅有一个实例,并提供一个访问它的全局访问点。
说人话
让这个类在整个程序中只有一个对象存在。
结构图
实现步骤
- 单例类
- 私有构造函数
- 静态变量 instance
- 静态方法 GetInstance 或只读属性 Instance 返回 instance
- 选择实现单例的模式
- 客户端使用 GetInstance 方法得到唯一对象
- 想实现单例的类继承泛型单例类,将自身当做泛型传入
说明
实现单例的模式主要包括:饿汉模式、懒汉模式、双重锁模式。
其他如枚举模式、Holder 模式、静态函数初始化模式等不太常用,故不作讲解。Lazy<T> 模式倒是可以看看,性能比双重锁好一些,且不用自己手动实现。
2.2 模版代码
饿汉模式
类加载时就创建,线程安全,可能造成资源浪费。
public class EagerSingleton
{
private static EagerSingleton instance = new EagerSingleton();
private EagerSingleton()
{
}
public static EagerSingleton GetInstance()
{
return instance;
}
}
懒汉模式
类使用时才创建,线程不安全,不会造成资源浪费。
public class LazySingleton
{
private static LazySingleton instance;
private LazySingleton()
{
}
public static LazySingleton GetInstance()
{
if (instance == null)
{
instance = new LazySingleton();
}
return instance;
}
}
双重锁模式
类使用时才创建,线程安全,不会造成资源浪费。
public class DoubleCheckedLockingSingleton
{
private static DoubleCheckedLockingSingleton instance;
private static readonly object lockObject = new object();
private DoubleCheckedLockingSingleton()
{
}
public static DoubleCheckedLockingSingleton GetInstance()
{
// 第一次检查,如果实例已经创建,则直接返回
if (instance == null)
{
lock (lockObject) // 使用锁来确保只有一个线程进入临界区
{
// 第二次检查,因为多个线程可以同时通过第一次检查
if (instance == null)
{
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
2.3 CSharp实践
实践需求
实现 饿汉模式 懒汉模式 双重锁模式 泛型单例 让要实现单例的类 通过继承泛型单例类时传入自身 来实现单例
饿汉模式
注意泛型单例构造函数要是保护的 否则子类继承时编译报错
public class EagerSingleton<T> where T : new()
{
private static T instance = new T();
protected EagerSingleton()
{
}
public static T GetInstance()
{
return instance;
}
}
双重锁模式
注意泛型单例构造函数要是保护的 否则子类继承时编译报错
public class LazySingleton<T> where T : new()
{
private static T instance;
protected LazySingleton()
{
}
public static T GetInstance()
{
if (instance == null)
{
instance = new T();
}
return instance;
}
}
双重锁模式
注意泛型单例构造函数要是保护的 否则子类继承时编译报错
public class DoubleCheckedLockingSingleton<T> where T : new()
{
private static T instance;
private static readonly object lockObject = new object();
protected DoubleCheckedLockingSingleton()
{
}
public static T GetInstance()
{
// 第一次检查,如果实例已经创建,则直接返回
if (instance == null)
{
lock (lockObject) // 使用锁来确保只有一个线程进入临界区
{
// 第二次检查,因为多个线程可以同时通过第一次检查
if (instance == null)
{
instance = new T();
}
}
}
return instance;
}
}
2.4 Unity实践
实践需求
实现继承Monobehavior的泛型单例类
MonoBehavior模式
继承MonoBehaviour类不会写构造函数 核心思想是假如没有单例就全局找 找不到创建对象添加脚本 Awake时检测
using UnityEngine;
public class MonoBehaviorSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
public static T GetInstance()
{
if (instance == null)
{
// 如果实例为空,则尝试在场景中查找具有类型 T 的对象
instance = FindObjectOfType<T>();
if (instance == null)
{
// 如果在场景中找不到该类型的对象,则创建一个新的游戏对象并将其作为单例
GameObject gameObject = new GameObject();
instance = gameObject.AddComponent<T>();
gameObject.name = typeof(T).ToString();
// 在场景加载时不销毁该游戏对象
DontDestroyOnLoad(gameObject);
}
}
// 返回单例对象
return instance;
}
protected void Awake()
{
if (instance == null)
{
// 如果实例为空,将当前对象设置为单例并在场景加载时不销毁
// 假如场景中有多个该脚本,那么总有一个会先进来instance==null
instance = this as T;
DontDestroyOnLoad(this.gameObject);
}
else
{
// 如果实例已存在,则销毁当前对象,以确保只有一个单例对象存在
Destroy(this);
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com