Unity中有很多特别的类需要以单例模式呈现,比如全局的UI管理类,各种缓存池,以及新手导航类等等。而Unity中,因为所有继承自Monobehaviour的脚本在实现的时候都是单线程的,所以像网上流传的一些C#的实现方式就显得不那么的实用了。

很多国内的公司所使用的MonoSingleton都是有问题的,比如像Easytouch中关于单例是这样实现中有这样一段代码。

        public static T instance
{
get
{
if (m_Instance == null)
{
m_Instance = GameObject.FindObjectOfType(typeof(T)) as T;//1这里耗费性能,有风险
if (m_Instance == null)//2
{
m_Instance = new GameObject("Singleton of " + typeof(T).ToString(), typeof(T)).GetComponent<T>();
m_Instance.Init();
}
}
return m_Instance;
}
}

  

那么我标注的两处就是代码当中不正确的地方。2处这是明显的套用了多线程的单例实现方式,而实际上,在单线程模式当中这个判断并没有意义。而1中,直接对全场景进行搜索的过程其本身就很浪费性能。那么正确的实现方式是什么呢?

首先,我们需要一个全局变量,比如,先建立一个全局类Global

public abstract class Global : MonoBehaviour
{
public static HashSet<string> Singleton=new HashSet<string>();
}

每次建立都将类名存进HashSet当中,那么上面那段代码就可以改成这样。

    public static T instance
{
get
{
if (m_Instance == null)
{
var name = "Singleton of " + typeof(T).ToString();
var flag = Global.Singleton.Contains(name);
if (!flag)
{
m_Instance = new GameObject(name, typeof(T)).GetComponent<T>();
m_Instance.Init();
Global.Singleton.Add(name);
}
}
return m_Instance;
}
}

可能您要说了,我已经有了一个全局类了,那么难道还要再填一个东西?我只想直接用,用没有更简便的方法。您要说更好,不一定,但是更简便,确实有的。我们这里可以用上互斥类Mutex的类,那么上面那段代码就可以改成下面这样:

    public static T instance
{
get
{
if (m_Instance == null)//注意,此处在实际中只执行一次。
{
bool createdNew;
var name = "Singleton of " + typeof(T).ToString();
Mutex mutex = new Mutex(false, name, out createdNew);
if (createdNew)
{
m_Instance = new GameObject(name, typeof(T)).GetComponent<T>();
m_Instance.Init();
}
}
return m_Instance;
}
}

但这只是说,我如果在其他地方操作这个单例,而这个单例还必须新建一个游戏物体,还必须挂在上面,挂在游戏物体上就至少要有一个transform组件。那么我可不可以直接挂在物体上,那该怎么办?如果我挂多了该怎么办?

有办法,这里我们利用Awake()方法

    private void Awake()
{
if (m_Instance == null)
{
bool createdNew;
var name = "Singleton of " + typeof(T).ToString();
Mutex mutex = new Mutex(false, name, out createdNew);
if (createdNew)
{
m_Instance = this as T;
m_Instance.Init();
}
}
else
{
Destroy(this);
}
}

这样就可以保证运行时的单例了。那么完整的MonoSingleton还需要一些细节。比如在我的单例基类中,我设计成抽象类,提供了两个抽象函数,分别是初始化和逆初始化。之所以这么做就是为了在我们继承MonoSingleton的时候想一想,是不是必须要把这个类做成单例的,它一定是有单例的必要所以才是单例的,而不是将单例当静态使用。

using UnityEngine;
using System.Collections;
using System.Threading;
/// <summary>
/// 单例基类,提供两个抽象函数Init 和 DisInit 初始化和逆初始化过程。
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class MonoSingleton<T> : MonoBehaviour
where T : MonoSingleton<T>
{ private static T m_Instance = null;
private static string name;
private static Mutex mutex;
public static T instance
{
get
{
if (m_Instance == null)
{
if ( IsSingle())
{
m_Instance = new GameObject(name, typeof(T)).GetComponent<T>();
m_Instance.Init();
}
}
return m_Instance;
}
} private static bool IsSingle()
{
bool createdNew;
name = "Singleton of " + typeof(T).ToString();
mutex = new Mutex(false, name, out createdNew);
return createdNew;
} private void Awake()
{
if (m_Instance == null)
{
if (IsSingle())
{
m_Instance = this as T;
m_Instance.Init();
}
}
else
{
Destroy(this);
}
} protected abstract void Init();
protected abstract void DisInit();
private void OnDestory()
{
if (m_Instance!=null)
{
mutex.ReleaseMutex();
DisInit();
m_Instance = null;
}
}
private void OnApplicationQuit()
{
mutex.ReleaseMutex();
}
}

  

  

  

  

  

MonoSingleton——Unity中的单例模式的更多相关文章

  1. Unity中C#单例模式使用总结

    一.单例模式优点 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问: 意味着在内存中,只存在一个实例,减少了内存开销: 二.单例模式特点 只存在唯一一个实例: ...

  2. 【Unity3D基础教程】给初学者看的Unity教程(七):在Unity中构建健壮的单例模式(Singleton)

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点推荐.谢谢! 该博客中的代码均出自我的开源项目 : 迷你微信 ...

  3. Unity中的万能对象池

    本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的万能对象池 本节通过一个简单的射击子弹的示例来介 ...

  4. 【《Effective C#》提炼总结】提高Unity中C#代码质量的21条准则

    作者:Williammao, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/290.h ...

  5. 【《Effective C#》提炼总结】提高Unity中C#代码质量的22条准则

    引言 原则1尽可能地使用属性而不是可直接访问的数据成员 原则2偏向于使用运行时常量而不是编译时常量 原则3 推荐使用is 或as操作符而不是强制类型转换 原则4 推荐使用条件属性而不是if条件编译 原 ...

  6. Unity中利用委托与监听解耦合的思路

    这篇随笔是一篇记录性的随笔,记录了从http://www.sikiedu.com/my/course/304,这门课程中学到的内容,附带了一些自己的思考. 一.单例模式的应用 首先假想一种情况,现在需 ...

  7. 【转】Effective C#观后感之提高Unity中C#代码质量的21条准则

    转自:http://blog.csdn.net/swj524152416/article/details/75418162 我们知道,在C++领域,作为进阶阅读材料,必看的书是<Effectiv ...

  8. Unity编程标准导引-3.4 Unity中的对象池

    本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的对象池 本节通过一个简单的射击子弹的示例来介绍T ...

  9. Unity中使用Attribute

    Attribute是c#的语言特性 msdn说明如下: The Attribute class associates predefined system information or user-def ...

随机推荐

  1. Codeforces Round #371 (Div. 1) C - Sonya and Problem Wihtout a Legend

    C - Sonya and Problem Wihtout a Legend 思路:感觉没有做过这种套路题完全不会啊.. 把严格单调递增转换成非严格单调递增,所有可能出现的数字就变成了原数组出现过的数 ...

  2. Java 基础总结大全

    Java 基础总结大全 一.基础知识 1.JVM.JRE和JDK的区别 JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. java语言是跨平台,jv ...

  3. 关于 bitset 的一些题目

    参考 http://www.cplusplus.com/reference/bitset/bitset/ https://blog.csdn.net/snowy_smile/article/detai ...

  4. 【HDU 6017】 Girls Love 233 (DP)

    Girls Love 233 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  5. 「BZOJ4763」雪辉

    「BZOJ4763」天野雪辉 题目大意:有一棵 \(n\) 个点的树,树上每一个点有权值 \(a_i \leq 30000\) ,每次询问给出若干路径,求出这些路径的并上面的不同颜色数与 \(mex\ ...

  6. 「LOJ6482」LJJ爱数数

    「LOJ6482」LJJ爱数数 解题思路 : 打表发现两个数 \(a, b\) 合法的充要条件是(我不管,我就是打表过的): \[ a + b = \text{gcd}(a, b)^2 \] 设 \( ...

  7. 「SCOI2014」方伯伯的商场之旅

    「SCOI2014」方伯伯的商场之旅 题目描述 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子.说来也巧,位置在 \(i\) 的人面前的第 \(j\) 堆的石 ...

  8. AtCoder Regular Contest 80

    链接 C. 4-adjacent 给定序列$a_i$,询问是否存在一个排列,满足$a_{p[i]}* a_{p[i + 1]}$是4的倍数 贪心构造 首先把只是2的倍数的数拿出来,放在最右边 前面把是 ...

  9. 2017-2018-1 JAVA实验站 冲刺 day01

    2017-2018-1 JAVA实验站 冲刺 day01 各个成员在 Alpha 阶段认领的任务 小组成员 分工 任务量 张韵琪 写博客.后期市场推广,营销.打杂.各职能的配合 齐力锋 提供宣传用图. ...

  10. 某DP题目3

    题意: 一根数轴上有n只怪物,第i个怪物所在的位置为ai,另有m个特殊点,第i个特殊点所在的位置为bi.你可以对怪物进行移动,若两怪物相邻,那么你不能把他们分开,移动时要看作一个整体.你可以选择向左或 ...