UnityにおけるVContainerを利用したDIコンテナ実装ガイド

本資料では、Unityの開発において従来のシングルトンパターンの課題と、代替としての依存性注入(DI)コンテナ利用の有用性について説明します。特に、Unity向けのDIコンテナであるVContainerを使用したサンプルコードを紹介し、柔軟でテスト容易な設計への移行方法を示します。



1. 背景

  • 依存性注入のメリット:
    DIコンテナを使用することで、コンポーネント間の依存関係が明示化され、保守性・テスト容易性が向上します。
  • VContainerの特徴:
    Unity向けの軽量なDIコンテナであるVContainerは、ライフサイクル管理や依存性の自動注入をサポートし、シーン上のMonoBehaviourにも対応しています。

2. サンプルコード

2.1 サービスの定義

まず、依存性注入の対象となるサービスのインターフェースとその実装クラスを定義します。

// IMyService.cs
public interface IMyService
{
    void DoSomething();
}
// MyService.cs
using UnityEngine;

public class MyService : IMyService
{
    public void DoSomething()
    {
        Debug.Log("VContainerを利用したサービスが動作しています。");
    }
}

2.2 LifetimeScope の設定

VContainerのLifetimeScopeを継承したクラスで、サービスおよびシーン上のMonoBehaviourを登録します。
ここで、RegisterComponentInHierarchy を利用して、シーン上に存在するMyBehaviourコンポーネントを自動注入の対象とします。

// GameLifetimeScope.cs
using VContainer;
using VContainer.Unity;

public class GameLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        // IMyServiceをシングルトンとして登録
        builder.Register<IMyService, MyService>(Lifetime.Singleton);

        // シーン上のMyBehaviourコンポーネントを自動注入対象として登録
        builder.RegisterComponentInHierarchy<MyBehaviour>();
    }
}

2.3 MyBehaviour の実装

依存性注入を受けるMonoBehaviourでは、[Inject]属性付きのメソッドで依存オブジェクトを受け取ります。

// MyBehaviour.cs
using UnityEngine;
using VContainer;

public class MyBehaviour : MonoBehaviour
{
    IMyService myService;

    // [Inject]属性により依存性が注入される
    [Inject]
    public void Construct(IMyService myService)
    {
        Debug.Log("MyBehaviourへの注入が実行されました。");
        this.myService = myService;
    }

    private void Start()
    {
        if (myService != null)
        {
            myService.DoSomething();
        }
        else
        {
            Debug.LogError("myServiceがnullです!");
        }
    }
}

3. Unityでのセットアップ手順

  1. GameLifetimeScopeの配置:
    空のGameObjectを作成し、そこにGameLifetimeScopeコンポーネントをアタッチします。
  2. MyBehaviourの配置:
    シーン上にMyBehaviourコンポーネントを持つGameObjectを配置します。
    ※ RegisterComponentInHierarchyを利用しているため、MyBehaviourのGameObjectは必ずしもGameLifetimeScopeの子でなくても構いませんが、シーン内に存在している必要があります。
  3. シーンの実行:
    シーンを再生すると、GameLifetimeScope内で依存性が登録され、MyBehaviourの[Inject]メソッドが実行されます。
    コンソールには「MyBehaviourへの注入が実行されました。」と表示され、その後「VContainerを利用したサービスが動作しています。」というメッセージが出力されます。

4. まとめ

  • RegisterComponentInHierarchyの利用:
    シーン上のMonoBehaviourも依存性注入の対象にするため、LifetimeScopeのConfigureメソッド内で必ずbuilder.RegisterComponentInHierarchy<MyBehaviour>();を追加する。
  • ログ出力で確認:
    [Inject]属性付きのメソッドにDebug.Logを追加し、注入処理が実際に実行されているかを確認することで、問題の切り分けが容易になります。

このサンプルを元に、プロジェクト内での依存性注入の実装を進めてください。