Unity单例模式基类全解析
目录
不继承MonoBehaviour的单例模式基类
继承MonoBehaviour的单例模式基类
挂载式的继承Mono的单例模式基类
自动挂载式的继承Mono的单例模式基类
解决构造函数带来的安全问题
解决重复挂载带来的安全问题
解决多线程带来的安全问题
是否加锁问题指什么?
解决多线程并发带来的问题
不继承MonoBehaviour的单例模式基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 单例模式基类 主要目的是避免代码的冗余 方便我们实现单例模式的类
/// </summary>
/// <typeparam name="T"></typeparam>
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;}}//方法的方式public static T GetInstance(){if (instance == null)instance = new T();return instance;}
}
继承MonoBehaviour的单例模式基类
挂载式的继承Mono的单例模式基类
容易破坏单例模式的唯一性
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 挂载式的继承Mono的单例模式基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{private static T instance;public static T Instance{get{ return instance;}}protected virtual void Awake(){instance = this as T;}
}
自动挂载式的继承Mono的单例模式基类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 自动挂载式的继承Mono的单例模式基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonAutoMono<T> : MonoBehaviour where T : MonoBehaviour
{private static T instance;public static T Instance{ get {if (instance == null){//动态创建 动态挂载GameObject gameObject = new GameObject(typeof(T).Name);instance = gameObject.AddComponent<T>();//过场景不移除 保证整个游戏声明周期只有一份DontDestroyOnLoad(gameObject);}return instance; }}}
解决构造函数带来的安全问题
1.父类变为抽象类
2.规定继承单例模式基类的类必须显示实现私有无参构造函数
3.在基类中通过反射来调用私有无参构造函数实例化对象
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;/// <summary>
/// 单例模式基类 主要目的是避免代码的冗余 方便我们实现单例模式的类
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseManager<T> where T : class
{private static T instance;//属性的方式public static T Instance{get {if (instance == null){ //instance = Activator.CreateInstance(typeof(T),true) as T;Type type = typeof(T);//利用反射得到无参私有的构造函数 来用于对象的实例化ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance|BindingFlags.NonPublic,null,Type.EmptyTypes,null);if (constructor != null)instance = constructor.Invoke(null) as T;elseDebug.LogError("没有得到对应的无参私有的构造函数");}return instance;}}//方法的方式public static T GetInstance(){if (instance == null){Type type = typeof(T);//利用反射得到无参私有的构造函数 来用于对象的实例化ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null,Type.EmptyTypes,null);if (constructor != null)instance = constructor.Invoke(null) as T;elseDebug.LogError("没有得到对应的无参私有的构造函数");}return instance;}
}
解决重复挂载带来的安全问题
解决重复挂载带来的安全问题
对于挂载式的单例模式脚本
1.同一个对象的重复挂载 ,为脚本添加特性[DisallowMultipleComponent]
//不允许在同一个对象上挂载多个相同的脚本
[DisallowMultipleComponent]
public class lessonTest : SingletonMono<lessonTest>
{public void TestLog(){print("lessonTest");}
}
2.修改代码逻辑, 判断如果存在对象,移除脚本
对于自动挂载式的单例模式脚本,制定使用规则,不允许手动挂载或代码添加
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 挂载式的继承Mono的单例模式基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{private static T instance;public static T Instance{get{ return instance;}}protected virtual void Awake(){//已经存在一个对应的单例模式对象了 不需要再有一个if (instance != null){Destroy(this);return;}instance = this as T;//我们挂载继承该单例模式基类的脚本后,依附的对象过场景时就不会被移除//就可以保证在游戏的整个生命周期中都存在DontDestroyOnLoad(this.gameObject);}
}
解决多线程带来的安全问题
是否加锁问题指什么?
如果程序当中存在多线程 ,我们需要考虑当多个线程同时访问同一个内存空间时出现的问题
如果不加以控制,可能会导致数据出错 ,我们一般称这种问题为多线程并发问题,指多线程对共享数据的并发访问和操作。
而一般解决该问题的方式,就是通过C#中的lock关键字进行加锁,我们需要考虑我们的单例模式对象们是否需要加锁(lock)
lock 的原理保证了在任何时刻只有一个线程能够执行被锁保护的代码块 ,从而防止多个线程同时访问或修改共享资源,确保线程安全
解决多线程并发带来的问题
1.不继承MonoBehaviour的单例模式 ,建议加锁,避免以后使用多线程时出现并发问题, 比如在处理网络通讯模块、复杂算法模块时,经常会进行多线程并发处理
2.继承MonoBehaviour的单例模式, 可加可不加,但是建议不加。
因为Unity中的机制是,Unity主线程中处理的一些对象(如GameObject、Transform等等),是不允许被其他多线程修改访问的,会直接报错 ,因此我们一般不会通过多线程去访问继承MonoBehaviour的相关对象,既然如何,就不会发生多线程并发问题
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;/// <summary>
/// 单例模式基类 主要目的是避免代码的冗余 方便我们实现单例模式的类
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseManager<T> where T : class
{private static T instance;//用于加锁的对象protected static readonly object lockObj = new object();//属性的方式public static T Instance{get {if (instance == null){lock (lockObj){if (instance == null){//instance = Activator.CreateInstance(typeof(T),true) as T;Type type = typeof(T);//利用反射得到无参私有的构造函数 来用于对象的实例化ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null,Type.EmptyTypes,null);if (constructor != null)instance = constructor.Invoke(null) as T;elseDebug.LogError("没有得到对应的无参私有的构造函数");}}}return instance;}}//方法的方式public static T GetInstance(){if (instance == null){lock (lockObj){if (instance == null){Type type = typeof(T);//利用反射得到无参私有的构造函数 来用于对象的实例化ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null,Type.EmptyTypes,null);if (constructor != null)instance = constructor.Invoke(null) as T;elseDebug.LogError("没有得到对应的无参私有的构造函数");}}}return instance;}
}
