Unity3D中实例和单例之间的区别

时间:2019-01-02 13:23:26

标签: c# unity3d singleton instance

我有一个基本问题,可以帮助新的团结伙伴更快地学习。如您所知,我们统一使用单例和类实例。我意识到了一件事情,我想确定自己在想什么。你能帮我确定吗?

在这种情况下,我会使用实例;

如果我有一个场景,并且想使用实例作为一层在脚本之间传输一些数据。我创建一个空的游戏对象,并将此代码分配为组件;

public class GameplayController : MonoBehaviour
{
    public static GameplayController instance;

    void Awake()
    {
        MakeInstance();
    }

    void MakeInstance()
    {
        if (instance == null)
        {
            instance = this;
        }
        else if(instance != null)
        {
            Destroy(gameObject);
        }
    }
}

在这种情况下,我会使用单例;

如果我有一个场景,并且我想使用单例模式作为一层在所有场景之间传输一些数据。我创建一个空的游戏对象,并将此代码分配为组件;

public class GameplayController : MonoBehaviour
{
    public static GameplayController instance;

    void Awake()
    {
        MakeSingleton();

    void MakeSingleton()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if(instance != null)
        {
            Destroy(gameObject);
        }
    }
}

所以,我想确定我是否走对了路?它一直有效到现在,但是将来在大多数高级情况下会出现问题吗?

1 个答案:

答案 0 :(得分:0)

您的代码是正确的,这是在Unity中创建单例的基本方法。

当您谈到Instance vs Singleton时,我得到的一些震动可能使您可能无法理解这个概念:Singleton的想法是对象只有一个(单个)实例。

因此,您拥有静态属性;类上的static修饰符使其无法使用new关键字进行修改。当您将其添加到属性中时(就像您已经做过的那样),这意味着您可以从任何地方访问它,而无需实例化包含类。

GameplayController.instance

在您的MakeInstance()中,验证该实例尚未分配给实例,然后将其设置为该实例。

要进一步遵循Singleton模式,您可能需要确保在加载新场景时不会破坏对象:

if (instance == null)
{
    DontDestroyOnLoad(gameObject);
    instance = this;
}

将来应该不会有任何问题; Singleton模式是一种不好的模式,但是它在原型制作中很有用。这很简单。

您可能会遇到的问题是,您的代码将具有对Singleton类的依赖关系,如果您忘记将类添加到场景中,或者如果您在较早的场景中必须实例化这些类,则会导致错误调试等时先启动该场景。

我个人使用Singleton类进行扩展,以确保在所有Singleton中具有相同的功能,并在每个Singleton类中减少膨胀,等等:

using UnityEngine;
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    private static T _instance;
    private static object _lock = new object();

    public static T Instance
    {
        get
        {
            if (applicationIsQuitting)
            {
                Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
                    "' already destroyed on application quit." +
                    " Won't create again - returning null.");
                return null;
            }

            lock (_lock)
            {
                if (_instance == null)
                {
                    var instances = FindObjectsOfType<T>();
                    if (instances.Length > 1)
                    {
                        Debug.LogError("[Singleton] Something went really wrong " +
                            ", there are too many Singletons; deleting them: ");
                        for (int i = 1; i < instances.Length; i++)
                        {
                            Debug.LogError("Deleting " + instances[i].gameObject.name);
                            Destroy(instances[i].gameObject);
                        }
                        _instance = FindObjectOfType<T>();
                        return _instance;
                    }

                    if (instances.Length > 0)
                        _instance = instances[0];

                    if (_instance == null)
                    {
                        GameObject singleton = new GameObject();
                        _instance = singleton.AddComponent<T>();
                        singleton.name = "[Singleton] " + typeof(T).ToString();

                        DontDestroyOnLoad(singleton);

                        Debug.Log("[Singleton] An instance of " + typeof(T) +
                            " is needed in the scene, so '" + singleton +
                            "' was created with DontDestroyOnLoad.");
                    }
                }

                return _instance;
            }
        }
    }

    private void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }

    /// <summary>
    /// When Unity quits, it destroys objects in a random order.
    /// In principle, a Singleton is only destroyed when application quits.
    /// If any script calls Instance after it have been destroyed, 
    ///   it will create a buggy ghost object that will stay on the Editor scene
    ///   even after stopping playing the Application. Really bad!
    /// So, this was made to be sure we're not creating that buggy ghost object.
    /// </summary>
    private static bool applicationIsQuitting = false;
    public void OnDestroy()
    {
        applicationIsQuitting = true;
    }
}

然后使用哪种方式:

public class MySingleton : Singleton<MySingleton>
{
     // Don't use the Awake method, Singleton uses it to initialize

     void Start() {
         Debug.Log("I'm a Singleton, access me through MySingleton.Instance");
     }
}