unity3d 单例模式的写法_unity单例模式写法 - CSDN
  • Unity单例写法

    2014-12-18 17:53:56
    如何在Unity中实现全局管理类?由于Unity脚本的运行机制和面向组件编程(COP)的思想,实现起来和普通的方式略有差别。  第一种方式是使用静态类。适合存储一些全局的变量,如游戏当前关卡、玩家得分等。 实现...
    如何在Unity中实现全局管理类?由于Unity脚本的运行机制和面向组件编程(COP)的思想,实现起来和普通的方式略有差别。

        第一种方式是使用静态类。适合存储一些全局的变量,如游戏当前关卡、玩家得分等。
    实现方式和普通的C#静态类没有差别。注意使用静态类就没有必要继承MonoBehaviour了。

    如果要实现复杂一些的全局控制,如切换游戏关卡等操作,更常用的方式是使用单例类。
    单例类的实现又分为两种:

    1.承自MonoBehaviour的单例类。
    2.纯C#的单例类。

    前者的优点是:
    1.可以在Inspector中显示,便于赋值和查看变量等;
    2.可以利用MonoBehaviour的接口;
    3.可以使用Coroutine等。
    缺点也很多,主流的观点是能不继承MonoBehaviour就不要继承。

    纯C#的单例类
    实现起来简洁,易于理解。
    普通的写法,不考虑多线程
    ?
    public class MyClass
    {
        private static readonly MyClass _instance = new MyClass();
        public static Class Instance { 
            get { 
                return _instance; 
            } 
        }    
     
        private MyClass() {}
    }




    线程安全的写法
    检查两次。C#中使用lock关键字。

    ?
    public class MyClass
    {
        private static volatile MyClass _instance;
        private static object _lock = new object();
     
        public static MyClass Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock(_lock)
                    {
                        if (_instance == null) 
                            _instance = new MyClass();
                    }
                }
                return _instance;
            }
        }
     
        private MyClass() {}
    }
    



    基于MonoBehaviour的单例类
    普通的写法
    利用了Unity的运行机制,从Awake处获取Unity创建的对象作为单例。
    注意在Unity中不要使用new来创建MonoBehaviour实例。
    ?
    public class MyClass : MonoBehaviour
    {
        static MyClass _instance;
     
        void Awake () {
            _instance = this;
        }
     
        public static MyClass Instance {
            get {
                // 不需要再检查变量是否为null
                return _instance;
            }
        }
    }



    持久化的写法
    在多个场景中保存单例。又有两种方法。
    第一种是使用DontDestroyOnLoad方法,告诉Unity不要销毁实例所在的对象,然后将脚本挂到某个GameObject上:
    ?
    public class MyClass : MonoBehaviour
    {
        static MyClass _instance;
     
        void Awake () {
            _instance = this;
            // 防止载入新场景时被销毁
            DontDestroyOnLoad(_instance.gameObject);    
        }
     
        public static MyClass Instance {
            get {
                return _instance;
            }
        }
    }




    上面这个方法有个弊端,必须要从挂载了这个单例的GameObject所在的场景启动,否则会找不到GameObject对象。但是开发和测试时我们经常会单独启动一个场景。

    另一种方法会创建一个GameObject,然后将单例挂载到其上:
    ?
    public class MyClass : MonoBehaviour {
     
        static MyClass _instance;
     
        static public MyClass Instance
        {
            get
            {
                if (_instance == null)
                {
                    // 尝试寻找该类的实例。此处不能用GameObject.Find,因为MonoBehaviour继承自Component。
                    _instance = Object.FindObjectOfType(typeof(MyClass)) as MyClass;
     
                    if (_instance == null)  // 如果没有找到
                    {                                       
                        GameObject go = new GameObject("_MyClass"); // 创建一个新的GameObject
                        DontDestroyOnLoad(go);  // 防止被销毁
                        _instance = go.AddComponent<MyClass>(); // 将实例挂载到GameObject上
                    }
                }
                return _instance;
            }
        }
    }



    展开全文
  • 为什么要使用单例模式 在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。  单例模式一般应用于管理器类,或者是一些需要持久化存在的...

    为什么要使用单例模式

    在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。 
    单例模式一般应用于管理器类,或者是一些需要持久化存在的对象。

    Unity3d中单例模式的实现方式

    (一)c#当中实现单例模式的方法

    因为单例本身的写法不是重点,所以这里就略过,直接上代码。 

    以下代码来自于MSDN。

    public sealed class Singleton 
    { 
       private static volatile Singleton instance; 
       private static object syncRoot = new Object(); 
       public static Singleton Instance 
       { 
          get  
          { 
             if (instance == null)  
             { 
                lock (syncRoot)  
                { 
                   if (instance == null)  
                      instance = new Singleton(); 
                } 
             } 
             return instance; 
          } 
       } 
    } 


    以上代码是比较完整版本的c#单例。在unity当中,如果不需要使用到monobeheviour的话,可以使用这种方式来构建单例。

    (二)如果是MonoBeheviour呢?

    MonoBeheviour和一般的类有几个重要区别,体现在单例模式上有两点。 
    第一,MonoBehaviour不能使用构造函数进行实例化,只能挂载在GameObject上。 
    第二,当切换场景时,当前场景中的GameObject都会被销毁(LoadLevel带有additional参数时除外),这种情况下,我们的单例对象也会被销毁。 
    为了使之不被销毁,我们需要进行DontDestroyOnLoad的处理。同时,为了保持场景当中只有一个实例,我们要对当前场景中的单例进行判断,如果存在其他的实例,则应该将其全部删除。 

    因此,构建单例的方式会变成这样。

    public sealed class SingletonMoBehaviour: MonoBehaviour
    { 
        private static volatile SingletonBehaviour instance; 
        private static object syncRoot = new Object(); 
        public static SingletonBehaviour Instance 
        { 
            get  
            { 
                if (instance == null)  
                { 
                    lock (syncRoot)  
                    { 
                        if (instance == null)  {
                            SingletonBehaviour[] instances = FindObjectsOfType<SingletonBehaviour>();
                            if (instances != null){
                                for (var i = 0; i < instances.Length; i++) {
                                    Destroy(instances[i].gameObject);
                                }
                            }
                            GameObject go = new GameObject("_SingletonBehaviour");
                            instance = go.AddComponent<SingletonBehaviour>();
                            DontDestroyOnLoad(go); 
                        }
                    } 
                } 
                return instance; 
            } 
        } 
    } 


    这种方式并非完美。其缺陷至少有: 
    * 如果有许多的单例类,会需要复制粘贴这些代码 
    * 有些时候我们也许会希望使用当前存在的所有实例,而不是删除全部新建一个实例。(这个未必是缺陷,只是设计的不同) 
    在本文后面将会附上这种单例模式的代码以及测试

    (三)使用模板类实现单例

    为了避免重复代码,我们可以使用模板类的方式来生成单例。非MonoBehaviour的实现方式这里就不赘述,只说monoBehaviour的。 
    代码

    public sealed class SingletonTemplate<T> : MonoBehaviour where T : MonoBehaviour
    {
        private static volatile T instance;
        private static object syncRoot = new Object();
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            T[] instances = FindObjectsOfType<T>();
                            if (instances != null)
                            {
                                for (var i = 0; i < instances.Length; i++)
                                {
                                    Destroy(instances[i].gameObject);
                                }
                            }
                            GameObject go = new GameObject();
                            go.name = typeof(T).Name;
                            instance = go.AddComponent<T>();
                            DontDestroyOnLoad(go);
                        }
                    }
                }
                return instance;
            }
        }
    }



    以上代码解决了每个单例类都需要重复写同样代码的问题,基本上算一个比较好的解决方案。

    单例当中的一些坑

    • 最大的坑是单例的monobehaviour,其生命周期并非我们程序员可以控制的。MonoBehaviour本身的Destroy,将会决定单例类的实例在何时销毁。因此,一定不要在OnDestroy函数中调用单例对象,这可能导致该对象在游戏结束后依然存在(原本的单例类已经销毁了,你又创建了一个新的,当然就不会再销毁一次了)。举例来说,以下的代码是需要注意的的。
    void Start(){
        Singleton.Instance.OnSomeTime += DoSth;
    }
    
    void OnDestroy(){
        Singleton.Instance.OnSomeTime -= DoSth;
    }


    • 此外,建议不要在场景或者预置当中放置拥有单例类组件的Gameobject。很多网上的项目有这样的写法。但我的观点是这种写法不够灵活。如果使用这种方法,注意在获取instance时,将找到的第一个对象赋给instance
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    T[] instances = FindObjectsOfType<T>();
                    if (instances != null)
                    {
                        instance = instances[0];
                        for (var i = 1; i < instances.Length; i++)
                        {
                            Destroy(instances[i].gameObject);
                        }
                    }
                }
                return instance;
            }
        }



    单例与静态的区别

    我们都知道,静态的成员或者方法,在整个Runtime当中也只有一份。所以一直存在着静态与单例模式之争。 
    事实上这两种方式都有其适用范围,不能片面的说某种好或某种不好。具体的争论实在是太多了,资料也多,这里也不深入讲,仅仅简单的说明一下两者使用上的区别。 
    * 单例的方法可以继承,静态的不可以。 
    * 单例存在着创建实例的过程,生命周期并不是整个运行时,静态方法在编译时就存在,整个过程中是一直有效的。 
    虽然两者的区别其实非常多,但在这里只说一个最核心的问题,如何进行选择?


    其实很简单,从面向对象的角度来说—— 
    * 如果方法中需要用到实例本身的状态,也就是说需要用到实例的成员时,这个方法一定是实例方法,请使用单例调用。 
    * 如果方法中完全不涉及到实例,而是类共享的一些状态的话,或者甚至不需要任何状态,这个方法一定是静态方法。 
    从应用的角度来说,我觉得以上就足够了,至于说内存占用的不同啊,GC以及效率上的区别啊这些我觉得更多是理论,不够贴近实际使用。

    单例虽好,请勿滥用

    滥用设计模式是很多人都会遇到的问题,尤其是对新手来说。设计模式应该只在合适的场景当中使用,而不是随处都使用单例。 
    事实上,单例的滥用会造成以下一些问题: 
    * 代码的耦合性可能会增加。如一个模块当中调用MusicController.instance.Play,可能导致这个模块无法独立复用。 
    * 单个类的职责可能会过大,违背单一职责原则。 
    * 某些情况下会造成一些性能问题。因为单例的对象永远不销毁,过多的单例会造成性能问题。 
    可以使用一些别的方法来代替单例模式,这里暂时不再扩展。

    单例的单例

    在某些情况下我会使用这种方法来构建唯一实例。 即在总单例类中声明了初始化其他的子单例类,方便了单例的统一获取和初始化。

    获取某个子单例的实例,可以用GameRoot.Instance.dbManager或DBManager.Instance。 

    作为更高一级的控制器的单例成员或者类变量,同样可以使该实例在整个游戏中仅存在一份。 
    其优势在于扩展性更好,因为我们可以随时添加单例的Controller类,等等。这里就不再扩展了。 

    using UnityEngine;
    
    public class GameRoot : MonoBehaviour {
    
        //数据读取管理类
        [HideInInspector]
        public DBManager       dbManager;
    
        //页面管理器
        [HideInInspector]
        public PageManager      pageManager;
    
        private static object _lock = new object();
        private static GameRoot _instance;
        public static GameRoot Instance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        GameObject go = new GameObject("GameRoot");
                        _instance = go.AddComponent<GameRoot>();
                    }
                }
                return _instance;
            }
        }
        private void Awake()
        {
            if (_instance == null)
            {
                _instance = this;
                _instance.Initialize();
            }
            else
            {
                Destroy(this);
                _instance = null;
            }
            DontDestroyOnLoad(this);
        }
    
    	void Initialize()
        {
            dbManager = gameObject.AddComponent<SqlManager>();
            dbManager.Init();
    
            pageManager = gameObject.AddComponent<PageManager>();
            pageManager.Init();
        }
    }
    


    DBManager单例类:


    public class DBManager : MonoBehaviour {
    
        private static DBManager _instance = null;
        public static DBManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = GameRoot.Instance.dbManager;
                }
                return _instance;
            }
        }
    }


    展开全文
  • 为什么要使用单例模式在我们的整个游戏生命...Unity3d中单例模式的实现方式(一)c#当中实现单例模式的方法因为单例本身的写法不是重点,所以这里就略过,直接上代码。 以下代码来自于MSDN。[csharp] view plain copy

    为什么要使用单例模式

    在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。 
    单例模式一般应用于管理器类,或者是一些需要持久化存在的对象。

    Unity3d中单例模式的实现方式

    (一)c#当中实现单例模式的方法

    因为单例本身的写法不是重点,所以这里就略过,直接上代码。 

    以下代码来自于MSDN。

    1. public sealed class Singleton   
    2. {   
    3.    private static volatile Singleton instance;   
    4.    private static object syncRoot = new Object();   
    5.    public static Singleton Instance   
    6.    {   
    7.       get    
    8.       {   
    9.          if (instance == null)    
    10.          {   
    11.             lock (syncRoot)    
    12.             {   
    13.                if (instance == null)    
    14.                   instance = new Singleton();   
    15.             }   
    16.          }   
    17.          return instance;   
    18.       }   
    19.    }   
    20. }   
    save_snippets.png
    public sealed class Singleton 
    { 
       private static volatile Singleton instance; 
       private static object syncRoot = new Object(); 
       public static Singleton Instance 
       { 
          get  
          { 
             if (instance == null)  
             { 
                lock (syncRoot)  
                { 
                   if (instance == null)  
                      instance = new Singleton(); 
                } 
             } 
             return instance; 
          } 
       } 
    } 


    以上代码是比较完整版本的c#单例。在unity当中,如果不需要使用到monobeheviour的话,可以使用这种方式来构建单例。

    (二)如果是MonoBeheviour呢?

    MonoBeheviour和一般的类有几个重要区别,体现在单例模式上有两点。 
    第一,MonoBehaviour不能使用构造函数进行实例化,只能挂载在GameObject上。 
    第二,当切换场景时,当前场景中的GameObject都会被销毁(LoadLevel带有additional参数时除外),这种情况下,我们的单例对象也会被销毁。 
    为了使之不被销毁,我们需要进行DontDestroyOnLoad的处理。同时,为了保持场景当中只有一个实例,我们要对当前场景中的单例进行判断,如果存在其他的实例,则应该将其全部删除。 

    因此,构建单例的方式会变成这样。

    1. public sealed class SingletonMoBehaviour: MonoBehaviour  
    2. {   
    3.     private static volatile SingletonBehaviour instance;   
    4.     private static object syncRoot = new Object();   
    5.     public static SingletonBehaviour Instance   
    6.     {   
    7.         get    
    8.         {   
    9.             if (instance == null)    
    10.             {   
    11.                 lock (syncRoot)    
    12.                 {   
    13.                     if (instance == null)  {  
    14.                         SingletonBehaviour[] instances = FindObjectsOfType<SingletonBehaviour>();  
    15.                         if (instances != null){  
    16.                             for (var i = 0; i < instances.Length; i++) {  
    17.                                 Destroy(instances[i].gameObject);  
    18.                             }  
    19.                         }  
    20.                         GameObject go = new GameObject(“_SingletonBehaviour”);  
    21.                         instance = go.AddComponent<SingletonBehaviour>();  
    22.                         DontDestroyOnLoad(go);   
    23.                     }  
    24.                 }   
    25.             }   
    26.             return instance;   
    27.         }   
    28.     }   
    29. }   
    save_snippets.png
    public sealed class SingletonMoBehaviour: MonoBehaviour
    { 
        private static volatile SingletonBehaviour instance; 
        private static object syncRoot = new Object(); 
        public static SingletonBehaviour Instance 
        { 
            get  
            { 
                if (instance == null)  
                { 
                    lock (syncRoot)  
                    { 
                        if (instance == null)  {
                            SingletonBehaviour[] instances = FindObjectsOfType<SingletonBehaviour>();
                            if (instances != null){
                                for (var i = 0; i < instances.Length; i++) {
                                    Destroy(instances[i].gameObject);
                                }
                            }
                            GameObject go = new GameObject("_SingletonBehaviour");
                            instance = go.AddComponent<SingletonBehaviour>();
                            DontDestroyOnLoad(go); 
                        }
                    } 
                } 
                return instance; 
            } 
        } 
    } 


    这种方式并非完美。其缺陷至少有: 
    * 如果有许多的单例类,会需要复制粘贴这些代码 
    * 有些时候我们也许会希望使用当前存在的所有实例,而不是删除全部新建一个实例。(这个未必是缺陷,只是设计的不同) 
    在本文后面将会附上这种单例模式的代码以及测试

    (三)使用模板类实现单例

    为了避免重复代码,我们可以使用模板类的方式来生成单例。非MonoBehaviour的实现方式这里就不赘述,只说monoBehaviour的。 
    代码

    1. public sealed class SingletonTemplate<T> : MonoBehaviour where T : MonoBehaviour  
    2. {  
    3.     private static volatile T instance;  
    4.     private static object syncRoot = new Object();  
    5.     public static T Instance  
    6.     {  
    7.         get  
    8.         {  
    9.             if (instance == null)  
    10.             {  
    11.                 lock (syncRoot)  
    12.                 {  
    13.                     if (instance == null)  
    14.                     {  
    15.                         T[] instances = FindObjectsOfType<T>();  
    16.                         if (instances != null)  
    17.                         {  
    18.                             for (var i = 0; i < instances.Length; i++)  
    19.                             {  
    20.                                 Destroy(instances[i].gameObject);  
    21.                             }  
    22.                         }  
    23.                         GameObject go = new GameObject();  
    24.                         go.name = typeof(T).Name;  
    25.                         instance = go.AddComponent<T>();  
    26.                         DontDestroyOnLoad(go);  
    27.                     }  
    28.                 }  
    29.             }  
    30.             return instance;  
    31.         }  
    32.     }  
    33. }  
    save_snippets.png
    public sealed class SingletonTemplate<T> : MonoBehaviour where T : MonoBehaviour
    {
        private static volatile T instance;
        private static object syncRoot = new Object();
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            T[] instances = FindObjectsOfType<T>();
                            if (instances != null)
                            {
                                for (var i = 0; i < instances.Length; i++)
                                {
                                    Destroy(instances[i].gameObject);
                                }
                            }
                            GameObject go = new GameObject();
                            go.name = typeof(T).Name;
                            instance = go.AddComponent<T>();
                            DontDestroyOnLoad(go);
                        }
                    }
                }
                return instance;
            }
        }
    }



    以上代码解决了每个单例类都需要重复写同样代码的问题,基本上算一个比较好的解决方案。

    单例当中的一些坑

    • 最大的坑是单例的monobehaviour,其生命周期并非我们程序员可以控制的。MonoBehaviour本身的Destroy,将会决定单例类的实例在何时销毁。因此,一定不要在OnDestroy函数中调用单例对象,这可能导致该对象在游戏结束后依然存在(原本的单例类已经销毁了,你又创建了一个新的,当然就不会再销毁一次了)。举例来说,以下的代码是需要注意的的。
    1. void Start(){  
    2.     Singleton.Instance.OnSomeTime += DoSth;  
    3. }  
    4.   
    5. void OnDestroy(){  
    6.     Singleton.Instance.OnSomeTime -= DoSth;  
    7. }  
    save_snippets.png
    void Start(){
        Singleton.Instance.OnSomeTime += DoSth;
    }
    
    void OnDestroy(){
        Singleton.Instance.OnSomeTime -= DoSth;
    }


    • 此外,建议不要在场景或者预置当中放置拥有单例类组件的Gameobject。很多网上的项目有这样的写法。但我的观点是这种写法不够灵活。如果使用这种方法,注意在获取instance时,将找到的第一个对象赋给instance
    1. public static T Instance  
    2. {  
    3.     get  
    4.     {  
    5.         if (instance == null)  
    6.         {  
    7.             T[] instances = FindObjectsOfType<T>();  
    8.             if (instances != null)  
    9.             {  
    10.                 instance = instances[0];  
    11.                 for (var i = 1; i < instances.Length; i++)  
    12.                 {  
    13.                     Destroy(instances[i].gameObject);  
    14.                 }  
    15.             }  
    16.         }  
    17.         return instance;  
    18.     }  
    19. }  
    save_snippets.png
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    T[] instances = FindObjectsOfType<T>();
                    if (instances != null)
                    {
                        instance = instances[0];
                        for (var i = 1; i < instances.Length; i++)
                        {
                            Destroy(instances[i].gameObject);
                        }
                    }
                }
                return instance;
            }
        }



    单例与静态的区别

    我们都知道,静态的成员或者方法,在整个Runtime当中也只有一份。所以一直存在着静态与单例模式之争。 
    事实上这两种方式都有其适用范围,不能片面的说某种好或某种不好。具体的争论实在是太多了,资料也多,这里也不深入讲,仅仅简单的说明一下两者使用上的区别。 
    * 单例的方法可以继承,静态的不可以。 
    * 单例存在着创建实例的过程,生命周期并不是整个运行时,静态方法在编译时就存在,整个过程中是一直有效的。 
    虽然两者的区别其实非常多,但在这里只说一个最核心的问题,如何进行选择?


    其实很简单,从面向对象的角度来说—— 
    * 如果方法中需要用到实例本身的状态,也就是说需要用到实例的成员时,这个方法一定是实例方法,请使用单例调用。 
    * 如果方法中完全不涉及到实例,而是类共享的一些状态的话,或者甚至不需要任何状态,这个方法一定是静态方法。 
    从应用的角度来说,我觉得以上就足够了,至于说内存占用的不同啊,GC以及效率上的区别啊这些我觉得更多是理论,不够贴近实际使用。

    单例虽好,请勿滥用

    滥用设计模式是很多人都会遇到的问题,尤其是对新手来说。设计模式应该只在合适的场景当中使用,而不是随处都使用单例。 
    事实上,单例的滥用会造成以下一些问题: 
    * 代码的耦合性可能会增加。如一个模块当中调用MusicController.instance.Play,可能导致这个模块无法独立复用。 
    * 单个类的职责可能会过大,违背单一职责原则。 
    * 某些情况下会造成一些性能问题。因为单例的对象永远不销毁,过多的单例会造成性能问题。 
    可以使用一些别的方法来代替单例模式,这里暂时不再扩展。

    单例的单例

    在某些情况下我会使用这种方法来构建唯一实例。 即在总单例类中声明了初始化其他的子单例类,方便了单例的统一获取和初始化。

    获取某个子单例的实例,可以用GameRoot.Instance.dbManager或DBManager.Instance。 

    作为更高一级的控制器的单例成员或者类变量,同样可以使该实例在整个游戏中仅存在一份。 
    其优势在于扩展性更好,因为我们可以随时添加单例的Controller类,等等。这里就不再扩展了。 

    1. using UnityEngine;  
    2.   
    3. public class GameRoot : MonoBehaviour {  
    4.   
    5.     //数据读取管理类  
    6.     [HideInInspector]  
    7.     public DBManager       dbManager;  
    8.   
    9.     //页面管理器  
    10.     [HideInInspector]  
    11.     public PageManager      pageManager;  
    12.   
    13.     private static object _lock = new object();  
    14.     private static GameRoot _instance;  
    15.     public static GameRoot Instance  
    16.     {  
    17.         get  
    18.         {  
    19.             lock (_lock)  
    20.             {  
    21.                 if (_instance == null)  
    22.                 {  
    23.                     GameObject go = new GameObject(“GameRoot”);  
    24.                     _instance = go.AddComponent<GameRoot>();  
    25.                 }  
    26.             }  
    27.             return _instance;  
    28.         }  
    29.     }  
    30.     private void Awake()  
    31.     {  
    32.         if (_instance == null)  
    33.         {  
    34.             _instance = this;  
    35.             _instance.Initialize();  
    36.         }  
    37.         else  
    38.         {  
    39.             Destroy(this);  
    40.             _instance = null;  
    41.         }  
    42.         DontDestroyOnLoad(this);  
    43.     }  
    44.   
    45.     void Initialize()  
    46.     {  
    47.         dbManager = gameObject.AddComponent<SqlManager>();  
    48.         dbManager.Init();  
    49.   
    50.         pageManager = gameObject.AddComponent<PageManager>();  
    51.         pageManager.Init();  
    52.     }  
    53. }  
    save_snippets.png
    using UnityEngine;
    
    public class GameRoot : MonoBehaviour {
    
        //数据读取管理类
        [HideInInspector]
        public DBManager       dbManager;
    
        //页面管理器
        [HideInInspector]
        public PageManager      pageManager;
    
        private static object _lock = new object();
        private static GameRoot _instance;
        public static GameRoot Instance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        GameObject go = new GameObject("GameRoot");
                        _instance = go.AddComponent<GameRoot>();
                    }
                }
                return _instance;
            }
        }
        private void Awake()
        {
            if (_instance == null)
            {
                _instance = this;
                _instance.Initialize();
            }
            else
            {
                Destroy(this);
                _instance = null;
            }
            DontDestroyOnLoad(this);
        }
    
        void Initialize()
        {
            dbManager = gameObject.AddComponent<SqlManager>();
            dbManager.Init();
    
            pageManager = gameObject.AddComponent<PageManager>();
            pageManager.Init();
        }
    }
    


    DBManager单例类:


    1. public class DBManager : MonoBehaviour {  
    2.   
    3.     private static DBManager _instance = null;  
    4.     public static DBManager Instance  
    5.     {  
    6.         get  
    7.         {  
    8.             if (_instance == null)  
    9.             {  
    10.                 _instance = GameRoot.Instance.dbManager;  
    11.             }  
    12.             return _instance;  
    13.         }  
    14.     }  
    15. }  
    save_snippets.png
    public class DBManager : MonoBehaviour {
    
        private static DBManager _instance = null;
        public static DBManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = GameRoot.Instance.dbManager;
                }
                return _instance;
            }
        }
    }


    展开全文
  • 单例模式有三大要点: 一、是每个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。 下面是几种写法: 一、 public class Singleton {  static Singleton instance;    ...

    单例模式有三大要点:

    一、是每个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

    下面是几种写法:
    一、
    public class Singleton
    {
        static Singleton instance;
     
        public static Singleton Instance {
            get {
                if (instance == null) {
                    instance = new Singleton ();
                }
                return instance;
            }
        }
    }
    二、
    public class Sigleton : MonoBehaviour
    {
        private static Sigleton instance;
    public  static Sigleton Instance
    {
    get{
    if (instance == null)
                {
                   instance = this ;
                }
                return instance;
    }
    }
        void Awake()
        {
            instance = this;
        }
    }
    三、
    public class Singleton<T> where T : new()
    {
    private static T instance;
    public static T Instance
    {
    get
    {
    if(instance == null)
    {
    instance = new T ();
    }
    return instance;
    }
    }
    }
    四、
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour

    {

    private static T instance;

            public static T Instance
           {
            get { return Singleton<T>.instance; }
           }
           void Awake()
          {
            if (instance == null)
             {
                instance = GetComponent<T>();
             }
          }
         void OnApplicationQuit()
         {
            instance = null;
            Debug.Log("quit");
         }
    }
    五、
    public  class Singletion<T> : MonoBehaviour where T : MonoBehaviour
    {
        private static string rootName = "SingletionRoot";
        private static GameObject SingletionRoot;


        private static T instance;
        public static T Instance
        {
            get
            {
                if (monoSingletionRoot == null)
                {
                    SingletionRoot = GameObject.Find(rootName);
                    if (SingletionRoot == null) Debug.Log("please create a gameobject named " + rootName);
                }
                if (instance == null)
                {
                    instance = SingletionRoot.GetComponent<T>();
                    if (instance == null) instance = SingletionRoot.AddComponent<T>();
                }
                return instance;
            }
        }
    }
    六、
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour{
        private static T instance;
        public static T Instance {
            get {
                if ( instance == null ) {
                    GameObject obj = new GameObject("Singleton");
                    // 隐藏实例化的new game object,下同
                    //obj.hideFlags = HideFlags.HideAndDontSave;    
                    // 不删除该物体
                    DontDestroyOnLoad(obj);
                    instance = obj.AddComponent(typeof(T)) as T;
                }
                return _instance;
            }
        }
    }


    七、
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour{
    private static object lock = new object();
    protected static T instance;
    public static T instance{
    get{
    lock(lock)
     {
      if(instance == null)
    {
    instance = FindObjectOfType<T>();
    if(instance == null)
    {
                            GameObject singleton = new GameObject();
       singleton.name = "Singleton_" + typeof(T).ToString();
       singleton.hideFlags = HideFlags.HideAndDontSave;
                                       instance = singleton.AddComponent<T>();
                                   }
                             }
                         return instance;
                     }
                  }
    }
    展开全文
  • 单例模式是所有设计模式之中运用最广泛的设计模式之一,而对象池...单例模式,简单说就是类的实例在内存中只存在一份,其中单例模式有2种写法: 首先,是继承自MonoBehaviour的单例,需要使用U3D组件和功能可以用...
  • 设计模式之单例模式
  • 最近在做切换场景的一款游戏时遇到了一个问题,场景和场景之间我需要相互传递并处理数据,于是就想到了单例,单例模式的共同优点就是只实例一次,节省内存。今天我想以个人理解总结一下单例模式。我一共列举了三种...
  • 主要目的:提高代码复用率 ...常规的单例对象写法 //UI管理器 public class MyUIManager { //静态唯一对象 private static MyUIManager _instance; public static MyUIManager GetInstance() { if (_
  • 今天我们就来看看在unity中如何使用单例模式,在unity中,我们分两种单例,一种是继承monobehavior的单例,一种是普通单例。 using UnityEngine; using System.Collections; public class Singleton : ...
  • Unity3d 单例对象池

    2016-12-05 11:04:23
    单例模式 初学者很容易搞晕,为啥有2种写法,这里顺带着写一下,不是本章的要点。 首先,是继承自MonoBehaviour的单例,需要使用U3D组件和功能可以用这种单例。理解U3D本身单例写法的机制就知道为啥要这么写了,第...
  • 写过C#代码的小伙伴,写单例模式时,习惯如下写法,用静态属性加私有构造函数,OK,一切看上去都不错。 但是,下面的代码,在UNITY中却怎么也不好使,因为继承自MonoBehaviour.  public class UIManager : ...
  • 单例模式4: 多线程二(双重锁定)这种双重锁定考虑了线程安全,是正规写法 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; n...
  • 使用时继承该单例类,不用管什么多线程之类的问题,也不用担心性能问题,因为在最开始的时候不管你要不要这个实例,都会被创建出来,所以只是在程序开始的时候消耗时间,到程序结束前不会销毁。 第一个是不继承...
  • unity用MVC设计模式一般要用Model层,而model层一般会用到单例模式,而单例写法有一摸一样,所以写个脚本偷懒一下吧一样的代码封装成基类,以后需要单例的model就继承这个积累就可以省去力气去敲单例的代码了。...
  • Unity单例模式

    2019-07-29 17:46:30
    为什么要使用单例模式 在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。...Unity3d中单例模式的实现方式 (一)c#当中实现...
  • 为什么要使用单例模式在我们的整个游戏生命...Unity3d中单例模式的实现方式(一)c#当中实现单例模式的方法因为单例本身的写法不是重点,所以这里就略过,直接上代码。 以下代码来自于MSDN。public sealed class Sing
  • 单例模式3: 多线程一 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 单例设计模式写法 { /...
  • 下面谈一下单例模式:简单地说就是一个static类,一个只能实例化一次并提供唯一接口的静态类。 最简单的单例模式,当然这是在没有继承自MonoBehaviour的C#类: public class Instance { private static Instance ...
  • 为什么要使用单例模式 在我们的整个游戏生命周期当中,有很多对象从始至终有且只有一个。这个唯一的实例只需要生成一次,并且直到游戏结束才需要销毁。 单例模式一般应用于管理器类,或者是一些需要持久化存在的...
  • 单例模式2: 单线程二(流行写法) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 单例设计模式写法 {...
1 2 3 4 5 6
收藏数 107
精华内容 42
关键字:

unity3d 单例模式的写法