当前位置:网站首页>Three singleton modes of unity (hungry man, lazy man, monobehavior)

Three singleton modes of unity (hungry man, lazy man, monobehavior)

2022-07-07 15:55:00 Listen to the rain outside the window

Unity The next three singleton modes

Single example usage scenario

​ The object is globally unique , And often used .

static Introduction to static fields

  1. All objects share static attribute , namely static Attributes are unique in this class .
  2. static Properties will not be GC Recycling , Create as the program begins , Destroy as the program ends (so Don't abuse single cases )

I've learned object-oriented buddy pairs static It must be no stranger , Its characteristics are very similar to the single case to be explained today , Naturally, the subsequent singleton mode will also be used .

warren :static Why are attributes uniquely shared in a class ?

​ C# All classes created in will have a globally unique type object (System.Type), The function table of this class will be saved in the type object , Static fields, etc , In other words, static fields are stored in globally unique type objects , Rather than exist in such new Out of the instance object , Now we can well explain the two properties of static fields .

Ordinary C# class — Hungry Chinese style

For better code reuse , The following three singleton patterns will adopt the design method of tool classes , That is, it is designed as a generic parent class , Subclasses that want to implement the singleton pattern only need to inherit the corresponding singleton tool class !

namespace Common
{
    
    /// <summary>
    ///  Hungry Chinese singleton mode generic parent 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Singleton<T> where T : Singleton<T> // Add generic constraint as T Must be itself or a subclass 
    {
    
        // Prevent objects from being created outside , Destroy uniqueness 
        protected Singleton() {
     }
        public static T Instance {
     get; private set; }

        // Static constructor , Called when the program starts 
        static Singleton()
        {
    
            Instance = Activator.CreateInstance(typeof(T), true) as T;
            Instance.Init(); // Initialize once 
        }

        /// <summary>
        ///  Optional initialization function 
        /// </summary>
        protected virtual void Init()
        {
    

        }
    }
}
  • Provide virtual functions Init, You can rewrite this Init Initialize the class , There is no need to use a constructor to prevent multiple calls .
  • Using generic delay to declare singleton schema objects , Subclasses can easily implement the singleton pattern by inheriting this parent class and assigning their own types to singletons ,where For generics T Constraints must be themselves or subclasses .
  • A single example of starving Chinese style , That is, at the beginning of the program, the singleton static attribute Instance To initialize , Two characteristics of hungry Han style
    • Starving singletons are thread safe ,static The constructor can only run once
    • Hungry Han style singleton has the risk of null reference , If in another class static This singleton is referenced in the constructor , Because of the running order, this singleton may not be instantiated yet , An empty reference error will be reported . This is in MonoBehavior It is particularly obvious in the single example of script !

Use a chestnut

using Common; // Note the reference to the namespace 
public class Test : Singleton<Test>
{
    
	private string str;
	protected override void Init()
	{
    
		base.Init();
		str = "Hello World";
	}
	
	public string SayHello()
	{
    
		return str;
	}
}


public class TestMono : MonoBehaviour
{
    
	private void Awake()
	{
    
		string str = Test.Instance.SayHello();
		Debug.Log(str);
	}
}

Ordinary C# class — Slacker type

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    
    /// <summary>
    ///  Singleton class lazy loading 
    /// </summary>
    public class SingletonLazy<T> where T:SingletonLazy<T>
    {
    

        private volatile static T instance;
        /*volatile modification : The compiler will fine tune the order of the code when compiling the code , use volatile Modification ensures the order of strict meaning .  One definition is volatile The variable is that it can be changed unexpectedly , such , The compiler will not assume the value of this variable .  To be precise, it means , The optimizer must carefully reread the value of this variable every time it is used , Instead of using a backup stored in a register .*/

        private static object locker = new object();
        public static T Instance {
     get
            {
    
                // Double check   Avoid multiple access thread lock and multi-threaded access conflict 
                if(instance == null)
                {
    
                    lock(locker)
                    {
    
                        if(instance==null)
                        {
    
                            instance = Activator.CreateInstance(typeof(T), true) as T;
                            instance.Init(); // Guaranteed to be called only once 
                        }
                    }
                }
                return instance;

            } }

        /// <summary>
        ///  Optional initialization function 
        /// </summary>
        public virtual void Init()
        {
    

        }
    }
}

  • An example of lazy style , Load on demand , Load the first time you use this object , There are also some characteristics of lazy singleton
    • Lazy singletons are non thread safe , There may be multiple calls at the same time , It will violate the globally unique feature of a singleton .
      • Multi thread conflict problem , Naturally, I think of using locks to isolate , Ensure that only one thread can be instantiated at the same time , In order to make the first thread instantiate , Subsequent threads that are locked and isolated will not be instantiated repeatedly when entering, and the internal part of the lock needs to be re checked and empty .
      • Due to the performance consumption of the lock , After the first instantiation , Subsequent call requests do not need to be blocked by locks before being judged null , A second check can be added outside the lock .
    • volatile In order to prevent address problems with minimal probability , In most cases, it can be ignored , If you want to pursue extreme rigor, you also need to add this attribute , The reason has been explained in the notes .

Script class — The hungry + lazy

namespace Common
{
    
    ///<summary>
    /// Script singleton class , Responsible for creating instances for unique scripts 
    ///<summary>

    public class MonoSingleton<T> : MonoBehaviour where T:MonoSingleton<T> // Note that this constraint is T Must be itself or a subclass 
    {
    
        private static T instance; // Create private object record value , You can assign values only once to avoid multiple assignments 

        public static T Instance
        {
    
            // Implement on-demand loading 
            get
            {
    
                // When it has been assigned , You can go back directly 
                if (instance != null) return instance;

                instance = FindObjectOfType<T>();

                // To prevent the script from hanging on the object , Exception not found , You can create an empty object and hang it 
                if (instance == null)
                {
    
                    // If you create an object , The script on it will be called when it is created Awake That is to call T Of Awake(T Of Awake Is actually the name of the inherited parent class )
                    // So there is no need to instance assignment , It will be in Awake Assignment in , It will initialize naturally, so there is no need to init()
                    new GameObject("Singleton of "+typeof(T)).AddComponent<T>();
                }
                else instance.Init(); // Guarantee Init Only once 

                return instance;

            }
        }

        private void Awake()
        {
    
            // If there are no other scripts Awake Call this instance , Then you can Awake Self initialization in instance
            instance = this as T;
            // initialization 
            Init();
        }

        // Subclasses initialize members if placed in Awake There will still be Null So make one by yourself init Function solution ( It's not necessary to use it )
        protected virtual void Init()
        {
    

        }
    }

}
  • Mono The singleton of the script is compared with ordinary C# Some change points of single case
    • Mono The instantiation method of script cannot rely on new, Instead, mount to GameObject On the body , If it is pre mounted in the scene, you can get it directly , If it is not mounted, it is automatically created GameObject And mount it .
    • Provide on-demand loading and initial loading , On demand loading is still get In the middle of , The initial load cannot be executed in the constructor , But in the script life cycle Awake Function .
    • Some people may wonder where objects are automatically created instance The problem of assignment , Actually create GameObject After AddComponent I'll do it once Awake If you assign another value Instance or Init It violates the characteristics of singleton .
  • Use this sophisticated Mono Singleton parent , At the same time, realize the hungry and lazy , There is no need to worry about Awake Null pointer exception caused by calling sequence , Just use it boldly !

ending

​ Singleton mode is a commonly used tool class , With these three scripts, you can encounter single case requirements in development , Direct inheritance is enough , Tool classes can greatly improve the speed of development , And there is no need to do a lot of repetitive work , Later, the author will gradually share the tool classes used in his development process !

原网站

版权声明
本文为[Listen to the rain outside the window]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071332216936.html