UnityのDIフレームワーク「Exenject(旧Zenject)」について使い方をまとめました。

DI(依存性の注入)とは?

デザインパターンの一つです。オブジェクトなどの間に生じる依存関係をオブジェクト内のコードに直接記述せず、外部から何らかの形で与えるようにする手法。

クラスAがクラスBに依存しているという情報を、クラスAの外で定義して外からクラスAのインスタンスに注入してあげることで疎結合なプログラムにするということですね。

Extenjectとは?

ExtenjectはZenjectのメンテナンス用として作られていましたが、今はZenjectはダウンロードできずExtenjectが公式となってます。

Extenject Dependency Injection IOC

Extenjectを使って各クラスの依存性を解消していきます。

Extenject入門① – クラスの注入

まずはHumanクラスにInputクラスの機能を注入するソースを書いてみます。
Aを押したら歩くInputとBを押したら歩くInput二つの機能を用意します。

public interface IInput
{
    void InputDown();
}

public class AInput : IInput
{
  bool InputDown(){
    return Input.GetKey(KeyCode.A);
  }
}

public class BInput : IInput
{
  bool InputDown(){
    return Input.GetKey(KeyCode.B);
  }
}

上記のクラスをExtenjectを使ってCharacterAに注入します。

public class CharacterA : Monobehaivor
{
    [Inject] IInput _input;
}

Extenject入門② – Installerの作成

ただ、このままではCharacterAはどちらのInputを注入するのか判断できません。
そこでExtenjectではInstallerを使って注入を行います。
AとBそれぞれのInstallerを作成します。

using Extenject;

public class AInputInstaller : Installer<AInput>
{
    public override void InstallBindings()
    {
        Container
            .Bind<IInput>()
            .To<AInput>()
            .AsCached();
    }
}
using Extenject;

public class BInputInstaller : Installer<BInput>
{
    public override void InstallBindings()
    {
        Container
            .Bind<IInput>()
            .To<BInput>()
            .AsCached();
    }
}

Extenject入門③ – Contextの作成

最後に、Installerの影響範囲決めとInstallerの登録を行います。

「GameObject > Extenject > Scene Context」からScene Contextを作成します。
作成されたSceneContextへAInputInstallerかBInputInstallerどちらかを入れることで完了です。
CharacterAに選択したInputInstallerが反映されます。

Extenject入門④ – Testの作成

さらにExtenjectではUnitTestも作成できます。
UnityTestRunnerを使ってEditorやPlayフォルダにテストファイルを格納しましょう。

InjectをTestファイル上で使用するには「ZenjectUnitTestFixture」を使用します。

擬似的にゲームオブジェクトを作成するにはMockフレームワークを作成します。

まとめ

Extenjectは慣れるまで学習コストがかかりますが、使いこなせば安全性の高いプログラムを組むことができます。是非お試しください。