Unityにおける依存管理・サービス提供パターン比較資料

1. 比較の目的

Unityでは、ゲーム全体で共有する機能(音声管理、セーブ処理、状態管理など)を「どのように提供・利用するか」が設計上の重要な課題です。

本資料では、以下の4つの方法を比較し、使用場面や適切な選定指針を明確にします。

  • Service Locator
  • Singleton
  • Dependency Injection (DI)
  • ScriptableObject(データ提供型)

2. 各パターンの概要とコード例

2.1 Service Locator

特徴

  • グローバルアクセスでサービスを取得
  • 実装の差し替えが可能

コード例(簡略)

ServiceLocator.Register<IAudioService>(new AudioService());
var audio = ServiceLocator.Get<IAudioService>();
audio.PlaySound("Jump");

2.2 Singleton

特徴

  • クラス内に唯一のインスタンスを保持
  • アクセスが簡単だが、差し替えが困難

コード例

public class AudioManager : MonoBehaviour
{
    public static AudioManager Instance { get; private set; }

    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
    }

    public void PlaySound(string name) { /*...*/ }
}

// 利用側
AudioManager.Instance.PlaySound("Jump");

2.3 Dependency Injection(明示的な依存注入)

特徴

  • 必要なサービスをコンストラクタやプロパティで渡す
  • テストしやすく、依存関係が明示される

コード例(非MonoBehaviour)

public class GameLogic
{
    private readonly IAudioService _audio;
    public GameLogic(IAudioService audio) { _audio = audio; }

    public void Jump() => _audio.PlaySound("Jump");
}

2.4 ScriptableObject

特徴

  • データや設定をアセットとして分離可能
  • デザイン時にインスペクタで差し替え可能

コード例

[CreateAssetMenu]
public class AudioConfig : ScriptableObject
{
    public AudioClip jumpClip;
}

public class Player : MonoBehaviour
{
    public AudioConfig config;
    void Jump() { AudioSource.PlayClipAtPoint(config.jumpClip, transform.position); }
}

3. 比較表

観点Service LocatorSingletonDependency InjectionScriptableObject
アクセスの容易さ高い(静的)高い(静的)低い(注入が必要)中(参照を要設定)
依存の明示性低い低い高い高い
テストのしやすさ低い非常に低い高い高い
柔軟な差し替え可能(手動)困難(コード変更)容易(注入で切替)容易(アセット切替)
初学者への導入難易度低い高い
Unityエディタ連携なしありなし(補助が必要)あり(インスペクタ活用)
主な用途実行時の動的切替単純な共通機能テスト可能な設計設定・定数・テーブル類

4. 使い分け指針

開発状況推奨パターン理由と補足
シンプルな常駐管理Singleton導入が最も容易。AudioManagerなどに向いている
テストや柔軟性を重視Dependency Injection明示的設計。モックの切替や再利用に最適
データや定数の共有ScriptableObject設定変更が容易。アセット経由でUIや敵パラメータなど
小規模でグローバル取得したいService Locatorクラス間を疎結合で保ちつつ、静的アクセスが可能
DIは使いたいがUnityに合わないScriptableObject + ServiceLocatorモックをScriptableObjectで切り替えれば組み合わせも可能

5. 結論

Unityでは用途に応じて以下のようなパターン使い分けが有効です。

  • 開発初期〜小規模 → Singleton / ScriptableObject
  • 中〜大規模 / テストが必要 → DI / Service Locator
  • 柔軟に切り替えたい設定 → ScriptableObject + Locator

導入の手軽さだけでなく、長期的な保守性・拡張性・チーム開発とのバランスを考慮して選択しましょう。