DIパターンとストラテジーパターンの違い
potatotipsで紹介されたKotlinのアプリのリポジトリを読んでいたら使ったことの無いlateinit
というAPIが出てきて、@Inject
というアノテーションがあるから、おそらくこれはDI
だな、と思ったのですが、よくわからず。
いつの間にかKotlinでなくDIの勉強をしていました。
DI(Dependency Injection)とは何なのか
まず最初に、下記の記事と、下記の参考に載っていた記事を読みました。
http://kazy.hatenablog.com/entry/2014/01/11/194142
http://www.atmarkit.co.jp/ait/articles/0504/29/news022.html
http://qiita.com/hshimo/items/1136087e1c6e5c5b0d9f
自分には上記の記事での依存という辺りの言葉遣いが分かり難かったので、もう少し噛み砕いてみます。
- DIは他のクラスのインスタンスを処理に利用する側のクラスと利用される側のクラスの話
- 便宜上、ここでは、利用する側のクラスをクライアント、利用される側で処理に必要な具体的な実行メソッドを持つクラスを具象クラスと呼ぶことにする
- 具象クラスのインスタンスをクライアントのコンストラクタなどで生成しているような状態はよくないですよね
- 具象クラスのインスタンスを実行時に*2代入することを「依存性を注入する」といっているらしい
- 例えば、テストの時などは、テストの実行時に具象クラスをモッククラス等に設定できるようにする、とか
そして、具体的な実装方法としては、クライアントが具象クラスの代わりに、インタフェースをプロパティに持つようにする、ということです。
もしかしたら、意味が分かり難くなるのは、日本語の略がやたら抽象的なせいかもしれず、依存性 => 具象クラスが継承しているインタフェース、あるいはインタフェースに括り出せる性質、くらいに捉えて良さそうです。
...なるほど。
Strategyパターンと何が違うのか
ところで、「Contextクラス(利用者側のクラス)がStrategyのインタフェース(抽象クラス)をプロパティに持っていて、必要に応じてStrategyの具象クラスを切り替えることが出来る」というような設計パターンをStrategyパターンとよびます。
DIパターンは、Strategyパターンと何が違うのでしょうか。
もう少し調べてみたら、下記の記事に当たりました。
http://www.infoq.com/jp/news/2007/12/does-di-pay-off
上記の記事から引用いたしますと、
あなたがGoFのファンであるなら、これは実際Strategyパターンなのです。 依存性注入は(私の見るところ)基本的にひとまとめに使われるStrategyパターンです。
はい、GoFファンです。ところで、ひとまとめに、というところが気になります。
もう少し、先ほどの記事を読んでみます。
DIフレームワークに依存するコードをひとたび書き始めると、オブジェクト接続に要する費用はほとんどゼロになります。
現実世界のシナリオでは、手動で行う依存性注入はただ単にスケールしないのです。
ふむふむ、さらに、
などを読みますと、
- Strategyパターンも、DIパターンもインタフェースをプロパティに持って、具象クラスを切り替えられるようにしている
- DIパターンを実装したフレームワークは、それを手動で行うのではなく、自動で行う方法を用意することで、具象クラスの切り替えを行いやすくしている
- 切り替える内容等を書いていく設定ファイルをDIコンテナという
ということみたいです。
実際、DI用ライブラリ(DaggerやGuice)は、具象クラスの代入処理と具象クラスの代入先/代入内容を設定するAPIを持っていますね。
小規模なアプリやテストの書きはじめですとそんなこともないのですが、大規模アプリだとあった方がテストを書くのが捗りそうです。
たとえば、自分のプロジェクトでは、RetrofitのMockClientのインスタンスとClientのパラメータを手動で書き換えててだるかったのですが、そういう場合に使えないか、検討してみると良さそうですね。
*1:http://qiita.com/mikamikuh@github/items/1cdcd8b25a2e23f10525
*2:あるいは、クライアントを呼び出しているコードブロックにおいて