统一使用Singleton的最佳方法

时间:2019-06-04 05:36:06

标签: c# unity3d

我想知道哪种方法是使用单例实例的正确方法:当我创建一个名为“ Manager”的单例类,并且它包含一个名为“ value”的int变量,而我又有一个名为“ A”的类... / p>

    //singleton class
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    public class Manager : MonoBehaviour {
        public static Manager Instance{ set; get;}
        public int value;
        private void Awake () {
            if (Instance == null) {
                Instance = this;
                DontDestroyOnLoad (this.gameObject);
            } else {
                Destroy (gameObject);
            }
        }
    }

因此,在我的A类中,我可以像下面这样创建单例的实例:         //示例伪代码         公共A级         {

        // First
        // using as a global variable
        Manager manager;

        //------------------------------------

        Public void tstOne(){
             // First
             // using that global variable
             manager.Instance.value = 0;

             // Second
             // or this way
             Manager.Instance.value = 0; 
        }
        Public void tstTwo(){
             // First
             // using that global variabl
             manager.Instance.value = 1;

             // Second
             // or this way
             Manager.Instance.value = 1; 
        }
    }

所以我的问题是-我应该创建一个全局实例,然后像第一个实例一样使用该实例,还是应该使用第二个实例?

它们在内存消耗和效率方面是否都相同? 还是有其他使用单例的方法?

3 个答案:

答案 0 :(得分:0)

Instance是一个静态字段,因此您应该使用Manager.Instance获取对单例的引用。

Manager.Instance是可全局访问的实例,因为它是公共静态的。 C#中没有像全局变量这样的东西。

直接通过类名访问静态字段绝对比在A中将第二个实例作为字段然后使用它访问静态实例要好。

答案 1 :(得分:0)

我确认了Ruzihm的回答(我也同意derHugo的评论,我个人更喜欢SO,并在需要时引用它们。比Singleton或DI直接方法干净得多)。

要特定地访问实例成员manager.Instance.value的速度较慢,并且还需要在堆上分配更多的内存,因此会损害内存使用率和速度性能。 (非常小的性能问题,但仍然如此。)

单身人士还有进一步的改进空间,尤其是如果您不要求它源自MonoBehaviour。

您可以:

  1. 如果您忘记将其添加到场景中,请确保它也是构建的
  2. 使其具有线程安全性(通常不需要团结)
  3. 懒惰地实现它(意味着您仅在需要时创建它)
  4. 此外,通常最好密封单例类以提高性能(使用虚拟方法时确实会稍有改善)

这就是实现方式(考虑到您使用Manager作为辅助实例,如果需要单行为逻辑,则使用YourManagerMono

public class YourManagerMono : MonoBehaviour
{
}

public sealed class Manager
{
    private static readonly Manager instance = new Manager();
    //use a gameobject to relate it in the scene
    private YourManagerMono monoManager;

    public static Manager Instance => instance;

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Manager() {}

    private Manager()
    {
        //find or create a manager
        monoManager = GameObject.FindWithTag("Manager").GetComponent<YourManagerMono>();
        if (monoManager == null)
        {
            monoManager = new GameObject().AddComponent<YourManagerMono>();
            monoManager.gameObject.tag = "Manager";
            Object.DontDestroyOnLoad(monoManager.gameObject);
        }
    }
}

Jon Skeet的C#出色的article about singleton实现(我使用了实现4)。

编辑:
我再次同意derHugo(在此答案的新评论中)。我的示例用于显示有趣的预期结果并提供尽可能多的性能,但是,如果您只需要单点1和3的Monohhaviour,则可以继续使用Unify Community的generic implementation of singleton(请记住,将结束类设置为密封的,以帮助编译器。

答案 2 :(得分:0)

对于只想在一个场景中存在的Singleton,我使用:

public class SceneSingleton<T> : MonoBehaviour
    where T : SceneSingleton<T>
{
    static T s_instance = null;

    public static T Instance
    {
        get
        {
            if (s_instance == null)
            {
                s_instance = Object.FindObjectOfType<T>();
            }

            return s_instance;
        }
    }
}

然后从中继承您的类,就像这样:

public class MyManager : SceneSingleton<MyManager>

如果您需要单身人士在所有场景之间保持活跃,请尝试使用以下方法:

public class GlobalSingleton<T> : MonoBehaviour
    where T : GlobalSingleton<T>
{
    static T s_instance = null;

    public static T Instance
    {
        get
        {
            if (s_instance == null)
            {
                GameObject prefab = Resources.Load(typeof(T).Name) as GameObject;

                if (prefab == null || prefab.GetComponent<T>() == null)
                {
                    Debug.LogError("Prefab for game manager " + typeof(T).Name + " is not found");
                }
                else
                {
                    GameObject gameManagers = GameObject.Find("GameManagers");
                    if (gameManagers == null)
                    {
                        gameManagers = new GameObject("GameManagers");
                        DontDestroyOnLoad(gameManagers);
                    }

                    GameObject gameObject = Instantiate(prefab);
                    gameObject.transform.parent = gameManagers.transform;

                    s_instance = gameObject.GetComponent<T>();
                    s_instance.Init();
                }
            }

            return s_instance;
        }
    }

   protected virtual void Init()
   { }
}
相关问题