MonoSingleton——Unity中的单例模式
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中的单例模式的更多相关文章
- Unity中C#单例模式使用总结
一.单例模式优点 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问: 意味着在内存中,只存在一个实例,减少了内存开销: 二.单例模式特点 只存在唯一一个实例: ...
- 【Unity3D基础教程】给初学者看的Unity教程(七):在Unity中构建健壮的单例模式(Singleton)
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点推荐.谢谢! 该博客中的代码均出自我的开源项目 : 迷你微信 ...
- Unity中的万能对象池
本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的万能对象池 本节通过一个简单的射击子弹的示例来介 ...
- 【《Effective C#》提炼总结】提高Unity中C#代码质量的21条准则
作者:Williammao, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/290.h ...
- 【《Effective C#》提炼总结】提高Unity中C#代码质量的22条准则
引言 原则1尽可能地使用属性而不是可直接访问的数据成员 原则2偏向于使用运行时常量而不是编译时常量 原则3 推荐使用is 或as操作符而不是强制类型转换 原则4 推荐使用条件属性而不是if条件编译 原 ...
- Unity中利用委托与监听解耦合的思路
这篇随笔是一篇记录性的随笔,记录了从http://www.sikiedu.com/my/course/304,这门课程中学到的内容,附带了一些自己的思考. 一.单例模式的应用 首先假想一种情况,现在需 ...
- 【转】Effective C#观后感之提高Unity中C#代码质量的21条准则
转自:http://blog.csdn.net/swj524152416/article/details/75418162 我们知道,在C++领域,作为进阶阅读材料,必看的书是<Effectiv ...
- Unity编程标准导引-3.4 Unity中的对象池
本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的对象池 本节通过一个简单的射击子弹的示例来介绍T ...
- Unity中使用Attribute
Attribute是c#的语言特性 msdn说明如下: The Attribute class associates predefined system information or user-def ...
随机推荐
- anaconda-anaconda无法安装pydot?
只需先安装graphviz,再安装pydot就可以了 sudo conda install graphviz sudo conda install pydot
- 【记录】mybatis-generator如何使用(maven方式)
1.首先在pom.xml中添加插件 <plugin> <groupId>org.mybatis.generator</groupId> <artifactId ...
- hdu 1158 dp Employment Planning
Employment Planning Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u ...
- mac系统终端下忽略大小写 与 git自动补全(git auto completion)
1.下载git-completion.bash 并放到home 目录下: curl https://raw.githubusercontent.com/git/git/master/contrib/c ...
- 【BZOJ 2839】 2839: 集合计数 (容斥原理)
2839: 集合计数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 399 Solved: 217 Description 一个有N个元素的集合有2 ...
- -【线性基】【BZOJ 2460】【BZOJ 2115】【HDU 3949】
[把三道我做过的线性基题目放在一起总结一下,代码都挺简单,主要就是贪心思想和异或的高斯消元] [然后把网上的讲解归纳一下] 1.线性基: 若干数的线性基是一组数a1,a2,a3...an,其中ax的最 ...
- 20162325 金立清 S2 W6 C15
20162325 2017-2018-2 <程序设计与数据结构>第6周学习总结 教材学习内容概要 队列是先进先出(FIFO)的集合 队列是保存重复编码k值的一种有效结构 实现模拟时常用队列 ...
- hibernate之条件查询
一.条件查询简介 条件查询是更据面向对象特色的数据查询方式,主要通过如下3个类完成 1.Criteria:代表一次查询 2.Criterion:代表一个查询条件 3.Restrictions:产生查询 ...
- PHP文件上传学习
PHP文件上传学习 <?php // 判断是否有文件上传 if (!isset($_FILES['upfile'])) { die('No uploaded file.'); } // 判断是否 ...
- [转]String.Replace 和 String.ReplaceAll 的区别
JAVA 中的 replace replaceAll 问题: 测试code System.out.println("1234567890abcdef -----> "+&qu ...