Zenjectについて学んでみる

はいどーもみなさんこんばんはニートです。
みなさん依存性の注入してますか。
僕はまだ依存性の注入の真髄がわかっていませんが、ボチボチしてる感じです。
というわけで本日は、Unityで依存性の注入をする際に便利なアセット「Zenject」について学んでみたいと思いますよ。

Zenjectとは

Zenjectとは、ズバリ依存性注入用のフレームワークです。
最も簡単な依存性の注入はコンストラクタでおこなうものでしょうが、なんやかんやで不便なことが多いですよね(特にUnityだと)。
そこでZenjectです。
これを用いると依存性の注入がやりやすくなります。
僕がZenjectを知ったのはつい今日のことなのですが、あまりの便利さについつい記事を書いてしまったレベルですよ。

とりあえず準備してみる

UnityのアセットストアからZenjectを入手してください。
GitHubからもDLできるっぽいです。
テスト用のプロジェクトにインポートしたら、以下のようなクラスとインターフェイスを作成してください。

大したことをしていないコードなのですが、一応少しだけ説明をしておきます。

各クラスはIPlayerAttackerインターフェイスを実装しています。
PlayerAttackerクラスは攻撃の回数をカウントしています。
他のクラスは単にログを出力しているだけです。

ここでは(多分)よくあるであろう「テスト用のものと本番用のもので生成するインスタンスを変えたいけど、Startメソッドとかでインスタンスを生成するのは何やかんやの理由で嫌だよ~」という問題を例にとってみます。

Zenjectを使ってみる

さて今のところまだZenjectっぽいコードは出てきていません。
単にZenjectをインポートして、下準備のコードを書いただけです。
ここからZenjectが活躍します。
ひとまず以下のようなクラスを作成してください。

Playerクラスを見てください。
_attackerフィールドにInject属性がついています。
Zenjectから依存性を注入させたい場合、このInject属性をつける必要があるようです。
PlayerクラスのUpdateメソッドを見てください。
このメソッドの中で_attackerフィールドが利用されています。
ところがこのクラス内には、具体的なインスタンスを生成しているコードがありません。
つまりnull参照エラーが出るはずです。
ですがInject属性をつけているおかげで、Zenject(AttackerInstallerクラス)がそのへんをうまいことやってくれるのです(この辺僕も内部で何が起きているのか、よく調べていません)。

AttackerInstallerクラスを見てください。
このクラスはZenjectから自動生成できるクラス(Create→Zenject→MonoInstaller)に、ちょびっと書き足しただけのクラスです。
InstallBindingsメソッドの中で依存関係を結びつけています。
意味としては「IPlayerAttackerインターフェイスを必要とするクラスには、PlayerAttacker型のインスタンスを与える。このインスタンスはシングルトンである」ということだと思います(まだよく調べられていないので細かい部分で間違いあるかも)。

動かしてみる

それではゲームを実行してみてください。
マウスをクリックすると「○回目の攻撃や!」と表示されると思います。
これはつまり、Playerクラスの_attackerフィールドに、AttackerInstallerクラスで指定したインスタンスが設定されていることを意味します。

試しにAttackerInstallerクラスの「PlayerAttacker」の部分を「DummyAttacker」や「PlayerCheatAttack」に変えてみてください。
きちんと変更されているのがわかるかなと思います。

Zenjectについてもう少し詳しく調べてみたい

基本的な使い方はわかったのですが、Zenjectはかなり機能が豊富なようです。
一朝一夕では使いこなせないレベルです。
とりあえず気になった部分を適当にメモします。

・AsSingle()の他にAsTransient()やAsCached()がある。
・AsTransientは、依存性の注入を要求されるたびに新しいインスタンスを作成している?(つまりシングルトンではない?)
・AsCached()とAsSingle()は何が違うのかよくわからない。要調査。
・Installerを使った方法以外もある
・MonoBehaviourを継承したオブジェクトにも使える

こんなところでしょうか。

おわりに

ZenjectのReadmeにこんなことが書かれてありました。

(原文)
Finally, I will just say that if you don’t have experience with DI frameworks, and are writing object oriented code, then trust me, you will thank me later! Once you learn how to write properly loosely coupled code using DI, there is simply no going back.
(訳)
最後にちょっといいですか。
もしあなたがDIフレームワークを使った経験がなく、OOPのコードを書いているならば、私を信用してください。
あなたは後で私に感謝することになりますから。
DIを使った、適切に疎結合されたコードを書く方法をいったん学んでしまえば、もう絶対に後戻りはできませんよ。

これはとても力強い言葉ですよね。
きっと他のフレームワークにも応用が効くでしょうし、僕はZenjectの作者さんを信用してDIフレームワークとやらを学んでいこうと思います。
ついでにUniRxも勉強したいなあ……。
勉強したいことだらけで困りますね。

ほなそんな感じでまた。
あ、お仕事も募集中です。

フォローする