【Unity】Zenjectで禅の心を手に入れる
Zenjectについて
導入を躊躇っていたものの、あるところから脅しがかかったので本格的に使い始めた
基本的な使い方などはこちらをご参考いただければわかるのではないかと思います
Unity3DのDIフレームワーク、Zenjectの紹介 | Aiming 開発者ブログ
今回はちょっと具体的な使い方を模索してみました。
何ができるのか
リポジトリのreadmeを読めばわかる
DI(Dependancy Injection)を行うためのライブラリで、すっごい簡単に言うと
newの引数とか、シングルトンで引っ張ってきてたオブジェクトを、登録しておいたオブジェクトの中から勝手に引っ張ってきて自動で参照を入れてくれるやつ
って認識でいいと思う、もちろんこれは機能のごく一部に過ぎない
他にもいろいろできる、公式読んで
中身の話
Zenjectの基本は
- Containerにオブジェクトを登録
- Containerに登録したオブジェクトをインスタンス化(この時に引数などの参照が自動で持ってこられる)
- オブジェクトが作られたらごにょごにょする
になる
Containerは、登録されたオブジェクトが入ってるDictionaryみたいなもので
ここの中にオブジェクトが登録されていないと、参照を解決できない
また、自動で参照してくれるようにするためには、参照先のオブジェクトも登録してあげないといけない
つまり、こう
これは全てにおいて適用されるので、まずBindを忘れないようにしよう。
使い方
まだ全てを把握できているわけではないので、状況別で
SingletonにしていたManagerを、Singletonにしない
(MonoBehaviour継承クラスに、参照を渡す方法)
Zenjectには、ZenjectBindingというコンポーネントが存在する
こいつは、登録したコンポーネントを勝手にContainerに登録してくれるすごいやつ
実際に使ってみるとこうなる
Managerの中身は、普通のMonoBehaviour継承クラスになっている
使用する場合は、こう書く
MonoBehaviour継承クラスの場合は、Injectアトリビュートを使用することで自動で参照が設定される
非継承の場合は、newで渡してあげる
これで、Managerは自動で使いたいところで使えるようになるので、ただのstatic参照のためだけにSingletonである必要がなくなる
もちろん、同一インスタンスが一つしかないことを保証するために使うのはあり
同一クラスは一つのみ生成し、あとはキャッシュを使う.AsSingle()というBind方法が存在する
同じことをしてる人がいたので、こちらも
余談ですが、torisoupさんはいつも勉強になる記事をあげてくださっているので定期購読をお勧めします
また、Manager以外にもZenjectBindingに登録さえすればなんでも使えます
Playerとかカメラとかを登録すると捗るかもね
Pureクラスを好きなタイミングでBindしながら生成する
MonoBehaviourの参照を渡したりするPureクラスとか・・・
クラスがごちゃごちゃしがちな原因の一つだが、Zenjectを使用することで解決出来る
まずMonoBehaviour継承クラスで渡したいクラスをBindする
- シーンに最初から直置きしてあればZenjectBindingを使用する
- 動的に生成される場合は、Container.Bindを使用してContainerに登録する
動的生成する際に勘違いされがちだが
別にInstallerを使って記述しなくてもいい
DIContainerへのBindさえできればよく、さらに
DIContainerはBindされているので好きなクラスにInjectで引っ張ってこれる
好きなタイミングでBindすればいいと思う
試しに、ボタンを押したらHogeをBindして生成するにはこうする
GameManagerはBindInstallerか何かでBindしてあげる必要があるが
BindさえすればDIContainerを引っ張ってこれるのでこういう書き方ができる
Container.Resolve<Hoge>()はBindされているオブジェクトをインスタンス化してreturnするメソッド
他にも.TryResolve<T>()などのメソッドが用意されているので、動的バインドする基底クラスかヘルパーを作ることをお勧めする
Resolveについては公式を
https://github.com/modesttree/Zenject#dicontainer-methods-resolve
ちなみに、BindされたPureクラスは明示的にUnBindしない限り参照を握られ続けるため破棄されない
Disposeメソッドなどを使い、破棄するタイミングでContainer.UnBind<Hoge>()を呼んであげよう
(これって非推奨だったりするのかな、知っている人がいたら教えてください)
その他
.FromNew
.FromMethodsとかは紹介したかったのですが、長くなりそうなのでまとめたときにでも
DIContainer.Inject
DiContainer.Instantiate
は今試してます。追記予定。
処理速度とかの測定はしてないんだけど、Bindは結構重いらしい
まあそうだろうねって感じだけど、これも測らないといけないね
終わり
禅の心強いわー