09. SingletonKit Singleton Template Kit

SingletonKit is the first tool collected by QFramework. After 7 years of iteration, it is now very mature.

Long time no see! I used to think that everyone could use QFramework directly, but later I thought that if the ongoing project uses QFramework directly, the risk is too high and there are too many codes to be changed. So I plan to gradually separate some tools and modules, allowing everyone to replace them module by module to reduce the risk of replacement.

QSingleton:

Several articles have introduced several implementations of singleton templates in Unity before. Later, I also referred to the implementation of other singleton libraries, learned from their advantages, and declared the original author.

Quick Start:

Implement a singleton class that inherits from MonoBehaviour

namespace QFramework.Example
{
    [MonoSingletonPath("[Audio]/AudioManager")]
    public class AudioManager : ManagerBase,ISingleton
    {
        public static AudioManager Instance
        {
            get { return QMonoSingletonProperty<AudioManager>.Instance; }
        }

        public void OnSingletonInit()
        {

        }

        public void Dispose()
        {
            QMonoSingletonProperty<AudioManager>.Dispose();
        }


        public void PlaySound(string soundName)
        {

        }

        public void StopSound(string soundName)
        {

        }
    }
}

The result is as follows:

This is very elegant from start to finish!

C# Singleton Class

  • Singleton.cs

public class GameDataManager : Singleton<GameDataManager>
{
    private static int mIndex = 0;

    private Class2Singleton() {}

    public override void OnSingletonInit()
    {
        mIndex++;
    }

    public void Log(string content)
    {
        Debug.Log(""GameDataManager"" + mIndex + "":"" + content);
    }
}

GameDataManager.Instance.Log(""Hello"");
// GameDataManager1:OnSingletonInit:Hello
GameDataManager.Instance.Log(""Hello"");
// GameDataManager1:OnSingletonInit:Hello
GameDataManager.Instance.Dispose();

Simply inherit QSingleton and declare a non-public constructor. If you need to get the timing of singleton initialization, you can choose to overload the OnSingletonInit method.

Result:

Hello World!
Hello World!

Mono Singleton

  • MonoSingleton.cs

public class GameManager : MonoSingleton<GameManager>
{
  public override void OnSingletonInit()
  {
      Debug.Log(name + "":"" + ""OnSingletonInit"");
  }

  private void Awake()
  {
      Debug.Log(name + "":"" + ""Awake"");
  }

  private void Start()
  {
      Debug.Log(name + "":"" + ""Start"");
  }

  protected override void OnDestroy()
  {
      base.OnDestroy();

      Debug.Log(name + "":"" + ""OnDestroy"");
  }
}

var gameManager = GameManager.Instance; // GameManager:OnSingletonInit // GameManager:Awake // GameManager:Start // ——————— // GameManager:OnDestroy

## Mono 属性单例
代码如下:

* MonoSingletonProperty.cs
```cs
public class GameManager : MonoBehaviour,ISingleton
{
    public static GameManager Instance
    {
        get { return MonoSingletonProperty<GameManager>.Instance; }
    }

    public void Dispose()
    {
        MonoSingletonProperty<GameManager>.Dispose();
    }

    public void OnSingletonInit()
    {
        Debug.Log(name + "":"" + ""OnSingletonInit"");
    }

    private void Awake()
    {
        Debug.Log(name + "":"" + ""Awake"");
    }

    private void Start()
    {
        Debug.Log(name + "":"" + ""Start"");
    }

    protected void OnDestroy()
    {
        Debug.Log(name + "":"" + ""OnDestroy"");
    }
}
var gameManager = GameManager.Instance;
// GameManager:OnSingletonInit
// GameManager:Awake
// GameManager:Start
// ---------------------
// GameManager:OnDestroy

C# 属性单例

代码如下:

  • SingletonProperty.cs

public class GameDataManager : ISingleton
{
  public static GameDataManager Instance
  {
      get { return SingletonProperty<GameDataManager>.Instance; }
  }

  private GameDataManager() {}

  private static int mIndex = 0;

  public void OnSingletonInit()
  {
      mIndex++;
  }

  public void Dispose()
  {
      SingletonProperty<GameDataManager>.Dispose();
  }

public void Log(string content) { Debug.Log(“”GameDataManager”” + mIndex + “”:”” + content); }


GameDataManager.Instance.Log(""Hello""); // GameDataManager1:OnSingletonInit:Hello

GameDataManager.Instance.Log(""Hello""); // GameDataManager1:OnSingletonInit:Hello

GameDataManager.Instance.Dispose();

```plain
## Rename MonoSingletPath


Code as follows:
MonoSingletonPath.cs:

```cs
namespace QFramework.Example
{
    using UnityEngine;

    [MonoSingletonPath("[Example]/MonoSingeltonPath")]
    class ClassUseMonoSingletonPath : QMonoSingleton<ClassUseMonoSingletonPath>
    {

    }

    public class MonoSingletonPath : MonoBehaviour
    {
        private void Start()
        {
            var intance = ClassUseMonoSingletonPath.Instance;
        }
    }
}

Result:

PersistentMonoSingleton

When there are two PersistentMonoSingleton in the scene, keep the one created first.

public class GameManager : PersistentMonoSingleton<GameManager>
{

}

IEnumerator Start()
{
    var gameManager = GameManager.Instance;

    var newGameManager = new GameObject().AddComponent<GameManager>();

    yield return new WaitForEndOfFrame();

    Debug.Log(FindObjectOfTypes<GameManager>().Length);
    // 1
    Debug.Log(gameManager == null);
    // false
    Debug.Log(newGameManager == null);
    // true
}

ReplaceableMonoSingleton

When there are two ReplaceableMonoSingleton in the scene, keep the one created last.

public class GameManager : ReplaceableMonoSingleton<GameManager>
{

}

IEnumerator Start()
{
    var gameManager = GameManager.Instance;

    var newGameManager = new GameObject().AddComponent<GameManager>();

    yield return new WaitForEndOfFrame();

    Debug.Log(FindObjectOfTypes<GameManager>().Length);
    // 1
    Debug.Log(gameManager == null);
    // true
    Debug.Log(newGameManager == null);
    // false
}

That’s all about the introduction of SingletonKit.