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. git上了github又要上码云。

    <h1>关联远程仓库:github为例</h1> 1.首先在用户目录下找到.ssh 2.如果.ssh文件夹里没有id_rsa和id_rsa.pub文件,或者也没有.ssh文件夹 ...

  2. poj2362 Square(DFS)

    题目链接 http://poj.org/problem?id=2362 题意 输入n根棍子的长度,求这n根棍子是否能组成一个正方形. 思路 假设能组成正方形,则正方形的周长为sum,sum/4为正方形 ...

  3. 【ASP.NET】:Ckeditor+Fckeditor的使用

    首先这三个文件:下载ckeditor和ckeditor_aspnet_3.6.4和ckfinder 然后把这三个文件复制到项目根目录下 添加引用CKEditor.NET.dll      CKFind ...

  4. c++ 单例模式研究

    一篇博文:C++ 单例模式的几种实现研究 中 看到的几段代码 懒汉模式 class Singleton { public: static Singleton* GetInstance() { if ( ...

  5. os.path.dirname(__file__)使用

    os.path.dirname(__file__)使用 该测试脚本所在的位置:D:\第1层\第2层\第3层\第4层\第5层\test11.py test11.py import os #该文件所在位置 ...

  6. HDU 3790最短路径问题 [最短路最小花费]

    题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=3790] 最短路径问题 Time Limit: 2000/1000 MS (Java/Others)  ...

  7. 安卓 Activity Fragment 生命周期

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 活动:  创建->启动->获得焦点->暂停->停止->销毁 ...

  8. [GCJ2017R2]Fresh Chocolate

    题目大意: 有n个团和很多盒糖,每个团中人数不一定相同,每盒糖中都有p颗糖. 现在要给每个团发糖,要求每个人都要发到糖,只有一盒糖发完后才能发下一盒糖. 发糖的顺序可以任意安排,问经过合理安排后,最多 ...

  9. lightoj 1296 - Again Stone Game 博弈论

    思路:由于数据很大,先通过打表找规律可以知道, 当n为偶数的时候其SG值为n/2; 当n为奇数的时候一直除2,直到为偶数m,则SG值为m/2; 代码如下: #include<stdio.h> ...

  10. 矩阵乘法快速幂 cojs 1717. 数学序列

    矩阵乘法模板: #define N 801 #include<iostream> using namespace std; #include<cstdio> int a[N][ ...