DIコンテナ - YuukiReiya/MyFramework GitHub Wiki
引用:https://soysoftware.sakura.ne.jp/archives/1955
DIとは
Dependency Injectionの略で、日本語では依存性注入と呼ばれてます。 DIとは、クラスのインスタンスの初期化時に、そのクラスが必要としてる他のインスタンスの参照をブチ込んであげる事です。
Unityユーザーは誰でもDIを使ってる!?
例えば... あるGameObjectのコンポーネントに、別のコンポーネントを参照させたい時は、 publicのフィールドを定義してから、インスペクタで参照を突っ込んであげますよね?
これもDIの一種です (初期化時に、インスペクタで指定しておいた通りに勝手に参照を解決してくれてますからね。)
つまり... Unityユーザーなら誰だってDIをバリバリ使いこなしてるという事になります。 Unityのシステム自体に便利にDIをやってくれる仕組みが内蔵されてるという事です。
何でDIコンテナなんてもんが必要なの?
普通のC#でのDI
Unityならエディタのシーンとインスペクタがあるおかげで、自由自在に依存関係を指定して、解決する事が可能でした。
しかし、普通のC#にはそういうエディタはありません。ぜ~んぶコードから自前で依存関係を解決してやる必要があります。コンストラクタから参照を渡してあげる、いわゆる手動DIって事ですね。
でもそれって面倒くさいですよね。
そこんとこを何とかしたいと思って考案されたのがDIコンテナです。
DIコンテナとは、読んで字のごとく、”DIしてくれるコンテナ”です。
コンテナというからには、何かを格納するんでしょうけど、何を格納するかといえば、クラスのインスタンスです。
つまるところ、DIコンテナの中には、他で使いたいクラスのインスタンスが一杯詰まっており、新しいインスタンス生成時に、必要な参照をコンテナの中身から自動的にブチ込んでくれます。(どのインターフェースに対してどの実体をブチ込むのか、あらかじめコードでルールを記述しておく必要があります)
UnityでのDIコンテナの役割
ZenjectやVContainerは、Unity向けのDIコンテナです。
どうして元々インスペクタで参照を解決できるUnity上でDIコンテナを使う必要なんてあるんでしょうか?
それはつまり、Unity世界と普通のC#世界を繋げるためです。
Unity向けのDIコンテナは、普通のDIコンテナと同様、普通のC#を扱う事ができる事に加えて、Monobehaviourのサポートが追加されてます。 普通のC#クラスにMonobehaviourの参照をブチ込むみたいな事ができるわけです。
ある意味で、前回の記事で書いた、インゲームの世界とアウトゲームの世界を繋げるという話でもあります。
Unityの世界をView的な世界と見なせば、View世界とModel世界を繋げるという見方もできるかもしれません。
Unity世界 | 普通のC#世界 |
---|---|
ダーティ | クリーン |
View | Model |
インゲーム(とUI) | アウトゲーム |
Monobehaviour | 普通のC# |
この分断された二つの世界を繋げるのがDIコンテナです。
ここからはMVPパターンで言うModelとかViewの用語が出てくるので、まだ読んでない人は前に書いたMVPの記事を読んでおくと理解がはかどります。
ModelをUnity世界から普通のC#世界に引っ越させる!?
Monobehaviourのデメリット
Monobehaviourはnewで生成できないので、普通のC#と比べてテストが書きにくいという問題もあります。
この辺が、Monobehaviourである事のデメリットと言えます。
クリーン的なモノの見方で言えば、Unityのシーンなんて、色んなオブジェクトが動的に生成、消滅してて、シーン上にいる限り、どこから誰がいつどんな操作を受けるか分からない、不確定要素が多すぎるダーティでView的な世界だと言えます。
普通のC#のデメリット
何と言っても、インスペクタで簡単に値を設定できるのがUnityの便利な所だったのに、普通のC#だとそれができなくなります。これがつらい。 エディタのプレイモード時に、値を変更する事もできなくなります。
また、全てがMonobehaviourだった頃は、シーンだけ見てればゲームの全体の動きが追えたのに、普通のC#世界が入り込んでくると追えない部分も出てきてしまいます。
つまりMonobehaviourも普通のC#も一長一短という事で、使い分けが大事になって来るでしょう。
とは言え、シーンを追ってデバッグしないといけないような入り組んだ問題が起きるのは大抵インゲームでしょうから、単にインゲームにはDIコンテナ使わない(インゲームは全部Viewだ!と考える)。みたいなスタンスでもいいのかもしれません。
DIツールとして何を利用すべき?
https://qiita.com/4_mio_11/items/4306732bc47780802b74 Zenject(Extenject)を入門してみた ・Zenject ・Extenject ・VContainer
こちらは元々「Zenject」というフレームワークをメインで管理していた方が、会社の退社後に個人でメンテを始めたフレームワークのようです。現在は「Extenject」の方が最新のUnityへの対応などが行われているため、これから使用する場合は「Extenject」をインポートすることをお勧めします。
Zenject/Extenjectどちらも更新が2020年で止まっているらしい。
https://vcontainer.hadashikick.jp/ja/
・高速なResolve: Zenjectとの比較でおよそ 5-10倍の性能 。 ・GCにやさしい: オブジェクト解決時 ゼロアロケーション 。(生成したインスタンス自身を除く) ・コンパクトなサイズ: internal 型や .callvirt 命令とかも少ない。ビルドサイズにやさしい。 ・過不足のない機能: シンプルで透明性のあるAPI。過度に複雑で理解し難い設定を避けます。 ・イミュータブルなコンテナ: 一度コンテナをつくったら遅い処理がほとんどない。スレッドセーフ。
2023/07 現在VContainer一択ぽい。