上一篇文章中说到的 manager of managers,其中每个 manager 都是单例的实现,当然也可以使用静态类实现,但是相比于静态类的实现,单例的实现更为通用,可以适用大多数情况。

如何设计这个单例的模板?

先分析下需求,当设计一个 manager 时候,我们希望整个程序只有一个该 manager 对象实例,一般马上能想到的实现是这样的:

  1. public class XXXManager
  2. {
  3. private static XXXManager instance = null;
  4. private XXXManager
  5. {
  6. // to do ...
  7. }
  8. public static XXXManager()
  9. {
  10. if (instance == null)
  11. {
  12. instance = new XXXManager();
  13. }
  14. return instance;
  15. }
  16. }

如果一个游戏需要10个各种各样的manager,那么以上这些代码要复制粘贴好多遍。重复的代码太多!!!想要把重复的代码抽离出来,怎么办?答案是引入泛型。实现如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Reflection;
  5. namespace QFramework
  6. {
  7. public abstract class QSingleton<T> where T : QSingleton<T>
  8. {
  9. protected static T instance = null;
  10. protected QSingleton()
  11. {
  12. }
  13. public static T Instance()
  14. {
  15. if (instance == null)
  16. {
  17. // 如何new 一个T???
  18. }
  19. return instance;
  20. }
  21. }
  22. }

为了可以被继承,静态实例和构造方法都使用protect修饰符。以上的问题很显而易见,那就是不能new一个泛型(3月9日补充:并不是不能new一个泛型,参考:new一个泛型的实例,编译失败了,为什么?-CSDN论坛-CSDN.NET-中国最大的IT技术社区),(4月5日补充:有同学说可以new一个泛型的实例,不过要求改泛型提供了public的构造函数,好吧,这里不用new的原因是,无法显示调用private的构造函数)。因为泛型本身不是一个类型,那该怎么办呢?答案是使用反射。实现如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Reflection;
  5. /// <summary>
  6. /// 1.泛型
  7. /// 2.反射
  8. /// 3.抽象类
  9. /// 4.命名空间
  10. /// </summary>
  11. namespace QFramework
  12. {
  13. public abstract class QSingleton<T> where T : QSingleton<T>
  14. {
  15. protected static T instance = null;
  16. protected QSingleton()
  17. {
  18. }
  19. public static T Instance()
  20. {
  21. if (instance == null)
  22. {
  23. // 先获取所有非public的构造方法
  24. ConstructorInfo[] ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
  25. // 从ctors中获取无参的构造方法
  26. ConstructorInfo ctor = Array.Find(ctors, c => c.GetParameters().Length == 0);
  27. if (ctor == null)
  28. throw new Exception("Non-public ctor() not found!");
  29. // 调用构造方法
  30. instance = ctor.Invoke(null) as T;
  31. }
  32. return instance;
  33. }
  34. }
  35. }

以上就是最终实现了。这个实现是在任何C#程序中都是通用的。其测试用例如下所示:

  1. using QFramework;
  2. // 1.需要继承QSingleton。
  3. // 2.需要实现非public的构造方法。
  4. public class XXXManager : QSingleton<XXXManager>
  5. {
  6. private XXXManager()
  7. {
  8. // to do ...
  9. }
  10. }
  11. public static void main(string[] args)
  12. {
  13. XXXManager.Instance().xxxyyyzzz();
  14. }

总结:

这个单例的模板是平时用得比较顺手的工具了,其实现是在其他的框架中发现的,拿来直接用了。反射的部分可能会耗一些性能,但是只会执行一次。在 Unity 中可能会需要继承 MonoBehaviour 的单例,因为很多游戏可能会只创建一个GameObject,用来获取 MonoBehaviour 的生命周期,这些内容会再下一讲中介绍:)。

转载请注明地址:凉鞋的笔记:liangxiegame.com

更多内容

Unity 游戏框架搭建 (二) 单例的模板的更多相关文章

  1. Unity 游戏框架搭建 (二十) 更安全的对象池

    上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...

  2. Unity 游戏框架搭建 (二十三) 重构小工具 Platform

    在日常开发中,我们经常遇到或者写出这样的代码 var sTrAngeNamingVariable = "a variable"; #if UNITY_IOS || UNITY_AN ...

  3. Unity 游戏框架搭建 (二十二) 简易引用计数器

    引用计数是一个很好用的技术概念,不要被这个名字吓到了.首先来讲讲引用计数是干嘛的. 引用计数使用场景 有一间黑色的屋子,里边有一盏灯.当第一个人进屋的时候灯会打开,之后的人进来则不用再次打开了,因为已 ...

  4. Unity 游戏框架搭建 (二十一) 使用对象池时的一些细节

    上篇文章使用SafeObjectPool实现了一个简单的Msg类.代码如下: class Msg : IPoolAble,IPoolType { #region IPoolAble 实现 public ...

  5. Unity 游戏框架搭建 (十三) 无需继承的单例的模板

    之前的文章中介绍的Unity 游戏框架搭建 (二) 单例的模板和Unity 游戏框架搭建 (三) MonoBehaviour单例的模板有一些问题. 存在的问题: 只要继承了单例的模板就无法再继承其他的 ...

  6. Unity 游戏框架搭建 (十) QFramework v0.0.2小结

    从框架搭建系列的第一篇文章开始到现在有四个多月时间了,这段时间对自己来说有很多的收获,好多小伙伴和前辈不管是在评论区还是私下里给出的建议非常有参考性,在此先谢过各位. 说到是一篇小节,先列出框架的概要 ...

  7. Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践

    Unity 游戏框架搭建 2018 (二) 单例的模板与最佳实践 背景 很多开发者或者有经验的老手都会建议尽量不要用单例模式,这是有原因的. 单例模式是设计模式中最简单的也是大家通常最先接触的一种设计 ...

  8. Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介

    约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ...

  9. Unity 游戏框架搭建 (十六) v0.0.1 架构调整

    背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...

随机推荐

  1. 在Linux下的找不同-打补丁

    Q:为什么要找不同,为什么要打补丁? A: 在Linux应用中,作为DBA,我们知道MySQL跑在Linux系统之上,数据库最重要的追求就是性能,"稳"是重中之重,所以不能动不动就 ...

  2. JSP servlet的配置与使用

    1. servlet 的配置文件内容如下所示 <servlet>     <description>This is the description of my J2EE com ...

  3. Workout Wednesday Redux (2017 Week 3)

    I had started a "52 Vis" initiative back in 2016 to encourage folks to get practice making ...

  4. springboot + shiro + cas4.2.7 实战

    1. 下载地址 https://github.com/apereo/cas/archive/v4.2.7.zip 2. 解压后, 用intellj idea 打开 3. 执行 gradle build ...

  5. 《HelloGitHub》第 14 期

    公告 欢迎通过在 GitHub 上新建 issues 方式推荐项目,我真心希望读者可以在 HelloGItHub,找到真正的编程乐趣! <HelloGitHub>第 14 期 兴趣是最好的 ...

  6. 传统平面广告已OUT出局,VR全景异军突起——VR全景智慧城市

    VR,近两年异军突起的"黑科技".从1935年斯坦利·温鲍姆首次在小说中描述VR眼镜,到如今PC头盔.VR分体机以及VR一体机的相继问世,VR自身已从虚拟走向现实.而当硬件迭代逐步 ...

  7. 从Thread,ThreadPool,Task, 到async await 的基本使用方法解读

    记得很久以前的一个面试场景: 面试官:说说你对JavaScript闭包的理解吧? 我:嗯,平时都是前端工程师在写JS,我们一般只管写后端代码. 面试官:你是后端程序员啊,好吧,那问问你多线程编程的问题 ...

  8. scroll抖动问题

    参考软文: http://www.cnblogs.com/coco1s/p/5499469.html function throttle(func, wait, mustRun) { var time ...

  9. WebSocket+MSE——HTML5 直播技术解析

    作者 | 刘博(又拍云多媒体开发工程师) 当前为了满足比较火热的移动 Web 端直播需求,一系列的 HTML5 直播技术迅速的发展起来. 常见的可用于 HTML5 的直播技术有 HLS.WebSock ...

  10. 论文笔记 Spatial contrasting for deep unsupervised learning

    在我们设计无监督学习模型时,应尽量做到 网络结构与有监督模型兼容 有效利用有监督模型的基本模块,如dropout.relu等 无监督学习的目标是为有监督模型提供初始化的参数,理想情况是"这些 ...