Разница между экземпляром и синглтоном в Unity3D - PullRequest
0 голосов
/ 02 января 2019

У меня есть основной вопрос, который может помочь новым ребятам из Unity учиться быстрее.Как вы знаете, в единстве мы оба используем singleton и экземпляр класса.Я понял одну вещь, и я хочу быть уверенным в том, что я думаю.Можете ли вы помочь мне быть уверенным?

Я использую экземпляр в некоторых ситуациях, подобных этой;

Если у меня есть сцена и я хочу использовать экземпляр в качестве слоя для передачи некоторых данных между сценариями.Я создаю пустой игровой объект и назначаю этот код в качестве компонента;

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 голосов
/ 02 января 2019

Ваш код верен, это основной способ создания синглтона в Unity.

Когда вы говорите об Instance vs Singleton, я получаю некоторые флюиды, которые вы, возможно, не понимаете: идея с Singletonявляется то, что будет только один (один) экземпляр объекта.

Итак, у вас есть статическое свойство;статический модификатор класса делает его не подлежащим определению с помощью ключевого слова new.Когда вы добавляете его к свойству (как вы это сделали), это означает, что вы можете получить к нему доступ из любого места, не создавая экземпляр содержащего его класса.

GameplayController.instance

В вашем MakeInstance () вы проверяете, что экземпляр еще не назначен экземпляру, а затем устанавливаете его для этого экземпляра.

Для дальнейшего следования шаблону Singleton вы, вероятно,хотите убедиться, что ваш объект не разрушен при загрузке новой сцены:

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

В будущем не должно быть никаких проблем;паттерн 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");
     }
}
...