Unity单例模式的使用
发表于2017-08-23
一.单例模式的基本实现:
单例模式(singleton pattern)大家都不陌生,我今天主要是和大家探讨一下单例模式在unity中的实现,比起一般的单例,unity中有些他的特点。
最普通的单例:(样式一)
- public class Singleton
- {
- static Singleton instance;
- public static Singleton Instance {
- get {
- if (instance == null) {
- instance = new Singleton ();
- }
- return instance;
- }
- }
- }
但是unity的所有脚本都必须挂在一个gameobject上,否则无法执行,你这个单例中若只是一些数据,那倒没关系,但我相信绝大多数单例模式都不会只包含数据,若只要实现包含数据的功能,用全局静态变量就行了,说到这里加一句,有些盆友喜欢用单例脚本当做全局脚本来用,那其实是违背单例模式的初衷的...
好,我们来实现以下挂到gameobject的单例(模式二):
- public class UnitySingleton : MonoBehaviour
- {
- static UnitySingleton instance;
- public static UnitySingleton Instance {
- get {
- if (instance == null) {
- instance = FindObjectOfType (typeof(UnitySingleton)) as UnitySingleton;
- if (instance == null) {
- GameObject obj = new GameObject ();
- instance = obj.AddComponent (typeof(UnitySingleton));
- }
- }
- return instance;
- }
- }
- }
Unity单例模式三:
那如果我的游戏里有很多单例脚本,每个脚本都这么写岂不是很麻烦?岂不是很违背oo思想?^_^,那我们来设计一个泛型类:
- public class UnitySingleton
: MonoBehaviour - where T : Component
- {
- private static T _instance;
- public static T Instance {
- get {
- if (_instance == null) {
- instance = FindObjectOfType (typeof(T)) as T;
- if (_instance == null) {
- GameObject obj = new GameObject ();
- obj.hideFlags = HideFlags.HideAndDontSave;//隐藏实例化的new game object,下同
- _instance = obj.AddComponent (typeof(T));
- }
- }
- return _instance;
- }
- }
- }
这样一来,场景中需要单例化的脚本只要简单的继承这个类就可以了
- public class SingletonTest : MonoBehaviour {
- // Use this for initialization
- void Start () {
- Debug.Log(Manager.Instance.testText);
- }
- }
Unity单例模式四:
最后一个问题就是,我希望我的所有单例脚本在场景变化后依然存在,那自然是用DontDestroyOnLoad,直接上脚本:
- using UnityEngine;
- public class UnitySingleton
: MonoBehaviour - where T:Component {
- private static T _instance;
- public static T Instance {
- get{
- if(_instance == null){
- _instance = FindObjectOfType(typeof(T)) as T;
- if(_instance == null){
- GameObject obj = new GameObject ();
- //obj.hideFlags = HideFlags.DontSave;
- obj.hideFlags = HideFlags.HideAndDontSave;
- _instance =(T) obj.AddComponent(typeof(T));
- }
- }
- return _instance;
- }
- }
- public virtual void Awake()
- {
- DontDestroyOnLoad(this.gameObject);
- if(_instance == null){
- _instance = this as T;
- }
- else{
- Destroy(gameObject);
- }
- }
- }
二.单例模式的高级使用
此种方式更加具有健壮性和灵活性,更加适合面向对象的基本思想“多组合,少继承”,更容易实现代码的维护和扩展。例如可以继续扩展对多个不同单例对象组件的管理
一位国外的程序猿在论坛上问:“在unity3D中,有木有什么萌萌哒方法可以创建一个类似全局类的静态实例一样的单例管理类啊!”
然后又说:“我该怎么做呢?需要把它挂在物体上吗?我能让它萌萌哒躺在文件夹里而不需要放在场景中吗”
下面就有位技术大大看到这个萌萌哒问题,心里顿时就软了,
然后很细心的告诉他了,这要看情况了,一般我用两种单例类:
1、作为组件挂在物体上
2、作为一个单独的类并且不继承字MonoBehaviour类
下面就是这个类的示例代码:
这个类主要由两部分组成:一个是用于单例管理的静态方法CreateInstance(),一个用于挂载组件的GameObject类型Main。
- public class MainComponentManger {
- private static MainComponentManger instance;
- public static void CreateInstance () {
- if (instance == null) {
- instance = new MainComponentManger ();
- GameObject go = GameObject.Find ("Main");
- if (go == null) {
- go = new GameObject ("Main");
- instance.main = go;
- // important: make game object persistent:
- Object.DontDestroyOnLoad (go);
- }
- // trigger instantiation of other singletons
- Component c = MenuManager.SharedInstance;
- // ...
- }
- }
- GameObject main;
- public static MainComponentManger SharedInstance {
- get {
- if (instance == null) {
- CreateInstance ();
- }
- return instance;
- }
- }
- public static T AddMainComponent
() where T : UnityEngine.Component { - T t = SharedInstance.main.GetComponent
(); - if (t != null) {
- return t;
- }
- return SharedInstance.main.AddComponent
(); - }
示例代码如下:
- public class AudioManager : MonoBehaviour {
- private static AudioManager instance = null;
- public static AudioManager SharedInstance {
- get {
- if (instance == null) {
- instance = MainComponentManger.AddMainComponent
(); - }
- return instance;
- }
- }