以前一直用着以下博客的单例模式的实现方法。
Unity Singleton 单例类(Unity3D开发之二十)
https://blog.csdn.net/cocos2der/article/details/47335197
今天看了《剑指Offer》第二版(下文简称为”书中“)P32实现单例模式的面试题2后,发现原来上面那种实现是书中提到不好的解法二。原因是使用了加锁这个比较耗时的操作,而且其实在实例创建后就不必再执行加锁操作了。
另外,它继承了MonoBehaviour,而很多时候我们使用的单例并不需要继承MonoBehaviour(尽量少继承)。
不过还有个问题就是:继承MonoBehaviour的类是不能被new出来的,所以如果单例想继承MonoBehaviour就不能直接使用书中的“强烈推荐的解法”,而是要像上面博客写得那样生成一个”DontDestroyOnLoad“ 的GameObject然后把单例类作为组件加上去。
OK,接下来请看代码
一、编写不继承MonoBehaviour的单例模板类(使用了书中强烈推荐的解法二)
PS:更简单的做法是直接用public static T Instance。那么为什么要用Nest隐藏类来创建Instance呢?因为如果该单例有静态方法的话,调用静态方法时就会调用public static T Instance而创建出单例,但其实有时候只用该类的静态方法是不需要创建Instance的,从而浪费了内存。使用Nest隐藏类就能做到真正的按需创建。
Singleton.cs
public class Singleton<T> where T : new()
{
public static T Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
static Nested() { }
internal static readonly T instance = new T();
}
}
编写单例类
class SingletonTest:Singleton<SingletonTest>
{
//类的实现
}
使用
SingletonTest.Instance.类的成员
二、编写继承MonoBehaviour的单例模板类(同上面博客所写的,但按照书中解法修改了加锁lock的位置,提高时间效率)
SingletonForMonoBehaviour.cs
public class SingletonForMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
private static object _lock = new object();
public static T Instance
{
get
{
if (applicationIsQuitting)
{
return null;
}
if (instance == null)
{
lock (lock)
{
_instance = (T)FindObjectOfType(typeof(T));
if (FindObjectsOfType(typeof(T)).Length > 1)
{
return _instance;
}
if (_instance == null)
{
GameObject singleton = new GameObject();
_instance = singleton.AddComponent<T>();
singleton.name = "(singleton) " + typeof(T).ToString();
DontDestroyOnLoad(singleton);
}
}
}
return _instance;
}
}
private static bool applicationIsQuitting = false;
public void OnDestroy()
{
applicationIsQuitting = true;
}
}
编写单例类
class SingletonTest:SingletonForMonoBehaviour<SingletonTest>
{
//类的实现
}
使用
SingletonTest.Instance.类的成员
如有问题,望不吝赐教。