Unityにおけるメソッド注入による依存性注入(DI)ガイド


Unityでは、C#の通常のコンストラクタを使用して依存性注入(DI)を行うことができません。しかし、メソッド注入を用いることで、依存するオブジェクトを外部から簡単に注入し、クラスの責務を分離し、テストのしやすさやコードの保守性を向上させることが可能です。本資料では、メソッド注入を用いた簡易的なDIの適用例について解説します。


1. メソッド注入の概要

メソッド注入とは、依存するオブジェクトや設定値をコンストラクタではなく、クラス内の特定のメソッドを通して外部から渡すDIの方法です。この方法を利用することで、Unityのライフサイクルに沿った形で依存性を柔軟に注入できるようになります。

メソッド注入の特徴

  • コンストラクタが使用できない環境でも利用可能(UnityのMonoBehaviourなど)。
  • 動的にオブジェクトを生成した後に依存性を注入できる。
  • クラス内部で直接Find()GetComponent()を使わずに依存するオブジェクトを注入できる。

2. GameDirectorへのメソッド注入適用例

まず、GameDirectorクラスに対して、依存するhpGaugeをメソッドで注入する方法を解説します。

元のコード

public class GameDirector : MonoBehaviour
{
    private GameObject hpGauge;

    void Start()
    {
        hpGauge = GameObject.Find("hpGauge");
    }

    public void DecreaseHp()
    {
        hpGauge.GetComponent<Image>().fillAmount -= 0.1f;
    }
}

リファクタリング後のコード(メソッド注入)

public class GameDirector : MonoBehaviour
{
    private Image hpGauge;

    // メソッドによる依存性の注入
    public void SetHpGauge(Image hpGauge)
    {
        this.hpGauge = hpGauge;
    }

    public void DecreaseHp()
    {
        hpGauge.fillAmount -= 0.1f;
    }
}

解説

  • 依存性の注入SetHpGauge()メソッドを用意し、hpGaugeオブジェクトを外部から注入できるようにしました。これにより、GameObject.Find()に依存しなくなり、柔軟性が向上します。

3. PlayerControllerへのメソッド注入適用例

次に、PlayerControllerでプレイヤーの移動距離を外部からメソッドで注入する方法について解説します。

元のコード

public class PlayerController : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            transform.Translate(-3, 0, 0);
        }
        else if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            transform.Translate(3, 0, 0);
        }
    }
}

リファクタリング後のコード(メソッド注入)

public class PlayerController : MonoBehaviour
{
    private float moveDistance;

    // メソッドによる依存性の注入
    public void SetMoveDistance(float moveDistance)
    {
        this.moveDistance = moveDistance;
    }

    void Update()
    {
        HandleMovement();
    }

    private void HandleMovement()
    {
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            Move(-moveDistance);
        }
        else if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            Move(moveDistance);
        }
    }

    private void Move(float distance)
    {
        transform.Translate(distance, 0, 0);
    }
}

解説

  • 依存性の注入SetMoveDistance()メソッドを使い、プレイヤーの移動距離を外部から設定可能にしました。これにより、プレイヤーの移動距離を動的に変更することができます。

4. メソッド注入のメリット

1. 柔軟性の向上

メソッドを通じて依存性を注入するため、クラスのライフサイクルの任意のタイミングで依存オブジェクトを設定できます。これにより、動的に生成されたオブジェクトにも適用可能です。

2. テスト容易性

モックオブジェクトを用いて、依存するオブジェクトを簡単に置き換えることができるため、単体テストや自動テストが容易になります。たとえば、SetHpGauge()にモックのImageを渡すことで、UIに依存しないテストが可能です。

3. 再利用性の向上

クラスが具体的な依存オブジェクトを管理せず、外部から注入されるため、再利用が容易です。例えば、PlayerControllerは移動距離が異なるさまざまなゲームでも簡単に再利用可能になります。


5. 使用例:クラスでの実装

1. GameManager.cs

GameManagerクラスは、各コンポーネントに依存性を注入する役割を持ちます。

using UnityEngine;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    void Start()
    {
        // GameDirectorにhpGaugeを注入
        GameObject directorObject = GameObject.Find("GameDirector");
        Image hpGauge = GameObject.Find("HpGauge").GetComponent<Image>();
        GameDirector director = directorObject.GetComponent<GameDirector>();
        director.SetHpGauge(hpGauge);

        // PlayerControllerに移動距離を注入
        GameObject playerObject = GameObject.Find("Player");
        PlayerController player = playerObject.GetComponent<PlayerController>();
        player.SetMoveDistance(3.0f);
    }
}
  • 役割GameManagerクラスは、GameDirectorPlayerControllerに必要な依存性(hpGaugeおよびmoveDistance)をセットアップします。このクラスは、ゲーム全体の初期設定や依存性の注入に使用されます。

2. GameDirector.cs

GameDirectorは、メソッド注入によりHPゲージを外部から設定します。

using UnityEngine;
using UnityEngine.UI;

public class GameDirector : MonoBehaviour
{
    private Image hpGauge;

    // メソッドによる依存性の注入
    public void SetHpGauge(Image hpGauge)
    {
        this.hpGauge = hpGauge;
    }

    public void DecreaseHp()
    {
        hpGauge.fillAmount -= 0.1f;
    }
}
  • 役割GameDirectorはHPゲージを管理し、プレイヤーがダメージを受けたときにHPゲージを減少させます。SetHpGauge()メソッドを使って、外部からHPゲージを設定できるようにしています。

3. PlayerController.cs

PlayerControllerは、移動距離を外部からメソッドで注入します。

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private float moveDistance;

    // メソッドによる依存性の注入
    public void SetMoveDistance(float moveDistance)
    {
        this.moveDistance = moveDistance;
    }

    void Update()
    {
        HandleMovement();
    }

    private void HandleMovement()
    {
        if (Input.GetKeyDown(KeyCode.LeftArrow))
        {
            Move(-moveDistance);
        }
        else if (Input.GetKeyDown(KeyCode.RightArrow))
        {
            Move(moveDistance);
        }
    }

    private void Move(float distance)
    {
        transform.Translate(distance, 0, 0);
    }
}
  • 役割PlayerControllerはプレイヤーキャラクターの移動を管理します。移動距離はSetMoveDistance()メソッドで外部から設定できるため、プレイヤーの動きが柔軟に変更可能です。

おわりに

メソッド注入は、UnityのC#コードで依存性注入を実現するためのシンプルで効果的な手法です。依存するオブジェクトをクラスの内部で直接管理するのではなく、外部から注入することで、クラスの柔軟性やテスト容易性が向上し、再利用性も高まります。UnityでDIを導入する際には、このメソッド注入を活用することで、よりモジュール化された設計を実現できます。

Unity

Posted by hidepon