Singleton مع المزالق

المقدمة


هناك عدد كبير من الأنماط ومضادات البرمجة. غالبًا ما يملي علينا استخدام الأنماط الخبرة والمعرفة الفعلية لأنفسهم. في هذه المقالة ، أود أن أناقش معك تطبيق نمط Singleton ، أي تنفيذه في Net كما هو مطبق على Unity.


سينجلتون


ألاحظ أنني أكتب رمزًا في فريق ، لذلك أقوم بأكبر قدر ممكن من العمل داخل الكود من أجل تفريغ الفريق وإلغاء الحاجة إلى التفكير في بعض الصعوبات في تنفيذ أنماط معينة في الوحدة.


دراسة الأدبيات على الشبكة 1 ، فيما يتعلق بهذا السؤال 2 ، ونتيجة للعمل في العديد من المشاريع ، ولد الصف التالي:


using UnityEngine;

/// <summary>
///    .
/// </summary>
/// <typeparam name="T">,    </typeparam>
/// <remarks>
///        OnDestroy  OnApplicationQuit
///      IsAlive.     
/// ,        .
/// 
/// 
///      Awake, OnDestroy, 
/// OnApplicationQuit    
/// base.Awake()  .
/// 
///    Initialization -      
///  .
/// 
///     unity,    
///   .    ,    
///       .
/// 
///  :
///     -  "CLR via C#"
///     - Chris Dickinson "Unity 2017 Game optimization"
///</remarks>

public class Singleton<T> : MonoBehaviour where T : Singleton<T>
{

    private static T instance = null;

    private bool alive = true;

    public static T Instance
    {
        get
        {
            if (instance != null)
            {
                return instance;
            }
            else
            {
                //Find T
                T[] managers = GameObject.FindObjectsOfType<T>();
                if (managers != null)
                {
                    if (managers.Length == 1)
                    {
                        instance = managers[0];
                        DontDestroyOnLoad(instance);
                        return instance;
                    }
                    else
                    {
                        if (managers.Length > 1)
                        {
                            Debug.LogError($"Have more that one {typeof(T).Name} in scene. " +
                                            "But this is Singleton! Check project.");
                            for (int i = 0; i < managers.Length; ++i)
                            {
                                T manager = managers[i];
                                Destroy(manager.gameObject);
                            }
                        }
                    }
                }
                //create 
                GameObject go = new GameObject(typeof(T).Name, typeof(T));
                instance = go.GetComponent<T>();
        instance.Initialization();
                DontDestroyOnLoad(instance.gameObject);
                return instance;
            }
        }

        //Can be initialized externally
        set
        {
            instance = value as T;
        }
    }

    /// <summary>
    /// Check flag if need work from OnDestroy or OnApplicationExit
    /// </summary>
    public static bool IsAlive
    {
        get
        {
            if (instance == null)
                return false;
            return instance.alive;
        }
    }

    protected void Awake()
    {
        if (instance == null)
        {
            DontDestroyOnLoad(gameObject);
            instance = this as T;
            Initialization();
        }
        else
        {
            Debug.LogError($"Have more that one {typeof(T).Name} in scene. " +
                            "But this is Singleton! Check project.");
            DestroyImmediate(this);
        }
    }

    protected void OnDestroy() { alive = false; }

    protected void OnApplicationQuit() { alive = false; }

    protected virtual void Initialization() { }
}

سأركز على عدة جوانب.


إنشاء كائن


عند توسيع المشروع ، بل والعمل أكثر كفريق> 3 أشخاص ، غالبًا ما تنشأ حالة عندما يصبح تسلسل إنشاء الكائنات غير واضح. بالمعنى الدقيق للكلمة 3 ، يكون تسلسل المكالمات إلى Awake () عشوائيًا (بالطبع ، هذا ليس صحيحًا تمامًا ، ويمكن أن تتأثر العملية ، ولكن الوثائق مقدسة) ، ولهذا السبب من الضروري القضاء على هذا العيب المزعج من خلال تنفيذ خاصية المثيل {get؛} . نتيجة لذلك ، نحصل على وصول كامل إلى المفرد من Awake () من الفئات الأخرى.


, Lazy, Awake() .

4-4, , Instance{get;}.



Unity — Awake(). , , Initialization(). (KISS).



, DI SD. . .



, , OnDestroy(), OnApplicationQuit() 5:


Did you spawn new GameObjects from OnDestroy?

, , , . , IsAlive(), , . , ...



لقد توصلت بشكل متزايد إلى استنتاج مفاده أنه باستخدام نموذج الوحدة من الممكن تنفيذ مشاريعي بدون Singleton. غالبًا ما يؤدي تطبيق هذا النمط إلى جعل الرمز الخاص بك متصلًا بشكل كبير وهش للغاية.


شكرا.


المصادر


- Richter J. "CLR via C #. البرمجة على Microsoft.NET # Framework 4.5 في C #" ، 2013


- https://www.codingame.com/playgrounds/1979/different-ways-to-implement-singleton-in--net-and-make-people-hate-you-along-the-way


- https://docs.unity3d.com/en/current/ScriptReference/MonoBehaviour.Awake.html


- https://ru.wikipedia.org/wiki/Design_Patterns


- ديكنسون كريس "Unity 2017 Game Optimization، Second Edition"، 2017


All Articles