Scala で DI (Effective Scala / Lift のDI編)

こんにちは、馬場です。

前回はScalaのDIのパターンとしては最も有名なCake Patternを紹介しました。今回はDIの他のパターンも紹介したいと思います。

Twitter でのScala DI

さて、少し前にTwitter がScala のベストプラクティスをgithub上に公開しました。DIについては、以下のように言っていますね(かなり意訳です)。

 Scala にmixinの仕組みを導入したのは、伝統的なDIの手法をやめたかったからだと思う。新方式の最たるものが「Cake pattern」だろう。
(略)
 けど、Scalaを利用するだけで、古典的DI手法の問題点はだいたい解決できると感じる。(略)だから、私たちはあまり継承せずに構造化しようと決めた。その方がモジュール性が高くテストしやすいプログラムができると思うから。

「伝統的なDIの手法」というのは、Springと同じようにコンストラクタで部品を設定していく方法です。取り替えたい部品のtraitを作成するところまではCake Pattenと一緒です。

ProfileServiceでTwitterApiを利用したいので、コンストラクタで渡します。

Scalaですので、コンストラクタ引数でFactory メソッドを渡す事もできます。こうすることにより部品の生成/設定が柔軟にできます。

コンテナにあたるobjectは以下のようになるでしょうか。

コード中で

のように、ComponentRegistryからprofileServiceを取得するところもCakePatternと同じです。このパターンを利用すれば、trait祭りが解消されるのでだいぶすっきりしていいですね。

Lift でのDI

CakePattern や Twitter のベストプラクティスでは、どのようにクラスをつくると取り替えやすいか、ということに注目していたと思います。対して、ComponentRegistryを高機能にして、場面ごとに適切なインスタンスを提供してもらうようにしよう、というのが、Liftです。

 Liftには、DI コンテナの基底となるSimpleInjectorというクラスがあります。SimpleInjector内では取り替え可能部品として利用したいクラスを以下のように宣言します。

TwitterApi そのものではなく、TwitterApiImplを引数にとるInjectというクラスを定義します。
TwitterApi を利用するProfileServiceでは以下のようにComponentRegistryからTwitterApiを取得します。

さてここからがSimpleInjectorの便利なところなのですが、SimpleInjectorはスコープ内で提供するクラスを変更する機能を持っています。
この機能を利用すると、テストメソッドは以下のようになるでしょう。

InjectのdoWithメソッドを利用すれば、関数ブロック内ではComponentRegistry.twitterApi.vendでモックのtwitterApiを取得できます。

このSimpleInjectorは、Lift のWeb アプリケーションを採用しなくても単独で利用可能なクラスですので、興味がある方はぜひ。

最後に

 ここまでScalaでのDIの方法をいろいろ紹介してきましたが、いかがだったでしょうか。個人的には、Twitter方式が一番すっきり、クラスが利用している部品、構成がわかりやすくいいな、と思いましたが、そこは私がOOに慣れているからかもしれません。いずれにしろ、Twitterさんの言うとおり、DIはモジュラリティとテスタビリティの向上のためには導入するべき、と断言します!まだまだ定番の方法がないScalaですが、いろいろ模索していきたいと思います。

Comments are closed, but you can leave a trackback: Trackback URL.