🎨

【Unity】デザインパターン SingleTon

2024/11/27に公開

Unityの開発では、ゲーム進行や設定管理、オーディオ管理といったクラスが
「プロジェクト内に1つだけ存在する」ケースがよくあります。
このようなクラスを効率的に管理するために利用される、
「シングルトンパターン」について調べたので、内容をまとめてみました。

シングルトンパターンとは?

  1. クラスのインスタンスを1つだけにすること
    ゲーム全体を管理するGameManagerなどは、複数存在すると混乱を招く可能性があります。
  2. そのインスタンスにグローバルアクセス可能にすること
    必要なときに、簡単にGameManager.Instanceとしてアクセスできるようになります。

これにより、特定のクラスを1つに限定し、プロジェクト全体で共有できます。

シンプルなシングルトン

public class SimpleSingleton : MonoBehaviour
{
    public static SimpleSingleton Instance;
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this; // 初回生成時にインスタンスを設定
        }
        else
        {
            Destroy(gameObject); // 2つ目以降のインスタンスを破棄
        }
    }
}

特徴

  • Instanceフィールドを利用して、シングルトンのインスタンスを保持します。
  • Awakeメソッドで、既存のインスタンスが存在する場合は破棄する仕組みです。
  • 注意点: この実装では、シーンをまたいでインスタンスを保持することはできません。

シーンをまたいで使うシングルトン

public class PersistentSingleton : MonoBehaviour
{
    public static PersistentSingleton Instance;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject); // シーンを切り替えても破棄されない
        }
        else
        {
            Destroy(gameObject); // 2つ目以降のインスタンスを破棄
        }
    }
}

特徴

  • 複数のシーンでインスタンスを保持するためには、DontDestroyOnLoadを使います。
  • この仕組みを使えば、設定データやスコア管理など、シーン間で共有する必要があるクラスに適用できます。

ジェネリックを活用した汎用的なシングルトン

実装例

public class Singleton<T> : MonoBehaviour where T : Component
{
    private static T instance;

    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                GameObject obj = new GameObject(typeof(T).Name);
                instance = obj.AddComponent<T>();
                DontDestroyOnLoad(obj);
            }
            return instance;
        }
    }

    private void Awake()
    {
        if (instance == null)
        {
            instance = this as T;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
}

利用例

public class GameManager : Singleton<GameManager>
{
    public int Score { get; set; }
}
  • シングルトンを複数クラスで再利用したい場合、ジェネリックを活用した実装が便利です。
  • GameManager.Instanceを利用して、どこからでもスコアを管理できます。

まとめ

シングルトンは、非常に便利で強力なデザインパターンですが、
使い方次第で大きなリスクを伴うこともあります。
安易に多用するとコードの独立性や可読性を損ない、
結果としてスパゲティコード化を招く危険性があります。
シングルトンを使用する際は、「本当に必要な場所にだけ利用する」という姿勢が重要です。

Discussion