Unity3D中实例和单例的区别

Difference between instance and singleton in Unity3D

我有一个基本问题可以帮助新手更快地学习。如您所知,在 unity 中我们都使用单例和 class 的实例。我已经意识到一件事,我想确定我在想什么。你能帮我确定一下吗?

我在这样的情况下使用实例;

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

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);
        }
    }
}

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

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

当您谈到实例与单例时,我得到了一些您可能不理解这个概念的感觉:单例的想法是对象只有一个(单个)实例。

所以你有一个静态的属性; class 上的 static 修饰符使其无法使用 new 关键字实例化。当您将它添加到 属性(就像您所做的那样)时,这意味着您可以从任何地方访问它,而无需实例化包含的 class。

GameplayController.instance

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

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

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

以后应该不会出问题的;然而,单例模式是一种糟糕的模式,但它在原型设计中有其用处;这很简单。

您可能遇到的问题是您的代码将依赖于您的单例 classes,如果您忘记将 class 添加到场景中,或者如果您有实例化这些 classes 的早期场景你必须在调试时首先启动该场景等

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

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");
     }
}