こんにちは!
株式会社OGIXのクライアントエンジニアのK.Iです。
今回はUnityで扱うDIコンテナについて、内部のDI(依存性注入)の構造まで深くご紹介します。
まずDIとは
DIは Dependency Injectionの略で、別名 依存性注入と呼びます。
プログラミングにおけるデザインパターンの一つで、オブジェクトを成立させるために必要となる
オブジェクトの参照を実行時に注入(Inject)する手法のことです。
DIという概念自体はとてもシンプルで、
オブジェクトの生成時に注入を行うコンストラクタインジェクション
生成後にメソッド経由で注入を行うメソッドインジェクションやセッターインジェクションなど
DIという用語を知らなくても、普段から行っているこれらの処理のことを示します。
Unityの GetComponent や SerializeField もDIの1つです
DIコンテナとは
DIコンテナはDI(依存性注入)を簡易的に行うための仕組みです。
Unityで有名なDIコンテナライブラリとして、以下のものがあります。
- Extenject(Zenject)
- VContainer
これらのライブラリでは、[Inject]属性をフィールドやメソッドに付与することで、DIコンテナが自動的に依存性の解決と注入を行います。
特にVContainerはコード数も少なく、DIが高速化される仕組みが備わっています。
こちらの機能を参考にDIコンテナを実装していきます。
DIコンテナに必要な機能
基本機能としては、登録(Register)と依存注入(Inject)が提供できれば機能を実現できます。
登録(Register)
今回は以下の登録方法を提供できるように実装していきます。
- T型からインスタンスの生成と登録ができる
- 既に生成されたインスタンスの登録ができる
- 同じ型の登録を行う場合に、既に登録されているインスタンスを保持し続けるか、新しいインスタンスに差し替えるかを選択することができる
実装したコードがこちらです。
依存性注入(Inject)
今回は、フィールドインジェクション(Field Injection) に焦点を当てています。
フィールドインジェクションが機能すれば、他の注入方法を使わなくても問題が生じにくいと考えています。また、フィールドインジェクションは一番宣言が簡潔であり、手軽に利用できる注入方法です。
ただし、注意すべき点として、コード上で明示的な代入が行われないため、初めて見る人にとっては少し違和感を感じるかもしれません。
まず、InjectAttributeを作成します。これによりフィールドに [Inject] 属性を付与できるようになります。
次に、DIContainerクラスのInjectメソッドを実装します。このメソッドはobject型の引数を受け取り、指定されたオブジェクトの全フィールドに対して[Inject]属性が付与されている場合、DIコンテナからの依存性の解決と注入を行います。
完成したコード
今回紹介しなかったメソッドで、ResolveとUnregisterを追加しています。
- Unregister は登録したインスタンスの解除
- Resolve は登録したインスタンスの取得(※メソッドの命名はZnjectを参考にしています)
使い方サンプル
実行後のログ結果
[Inject]属性を付与することで、DIされていることが確認できます。
まとめ
いろいろ紹介しましたが、VContainerを使うのがおすすめです。しかし、ライブラリとして提供されているため、多くの機能が提供されており、初めて使う方には取っつきにくいと感じることもあるかもしれません。しかし、今回のシンプルな実装では本当に必要な機能だけに焦点を当てることができます。
各工程の処理の流れも追いやすくなり、結果としてDIコンテナの仕組みや概念を理解しやすいと思いますので、参考にしてみてください!
一緒に働く仲間を募集しています!
株式会社OGIXでは一緒に働いてくれる仲間を募集しています!
エンタメ制作集団としてゲームのみならず、未来を見据えたエンタメコンテンツの開発を行っています。
事業拡大に伴い、エンジニアさんを大募集しています。
皆さまのご応募、心よりお待ちしております!