ScalaとGoogle Guiceの組み合わせについて軽く調べた

あまり目新しい内容ではないですが、Google Guice理解のために、改めてまとめました。

## ScalaにおけるDI
Javaなどの言語と同様に、Scalaにおいても依存性注入(DI)を実現する方法はいくつかあるようです。

1. Constructor InjectionやSetter Injectionを使う
2. Cake PatternなどのScala特有の言語機能を使った方法
3. (Google Guiceなどの)DIフレームワークを使う
4. 構造的部分型を使うetc....

この記事では3.のGoogle Guiceを使う方法について調べました。そういえばPlay  Frameworkの2.4でも導入されるとか聞いたような……？

## Google Guiceの基本的な使い方（Java）
いくつかの典型的なパターンと比較しているという点でも、[公式のチュートリアル](https://github.com/google/guice/wiki/Motivation)がとても分かりやすいかなと思います。GuiceはもともとJava用なので、Javaで書いてある……。

大事な部分だけ抜き出すとこんな感じ。

```java
interface Service {
    void doSomething();
}

class RealService implements Service {
    @Override
    public void doSomething() {
        // .....
    }
}

class FakeService implements Service {
    @Override
    public void doSomething() {
        // .....        
    }
}
```

やりたいことは、`RealService`と`FakeService`どちらを使うかを状況によって切り替えることです。例えばテスト時にだけ`FakeService`を使うようにしたい。そして、どの具体的な実装を使うかという知識は、`Service`とは離れた場所に持たせたい。Guiceでは次のようなお作法に従ってDIを実現するようです。

- 依存性を注入されるクラスでは、依存関係にあるクラスをコンストラクタで受け取る
    - コンストラクタには`@Inject`アノテーションを付けておく
- どう配線するか（どのインタフェースにどの具体的な実装を入れるか）はModuleにまとめる
- `Guice.createInjector`を用いることで、ModuleからInjectorを生成する
- `Injector`の`getInstance`メソッドを呼ぶことで、Moduleで記述された参照関係に基づいて実際のインスタンスが得られる

このルールに基づいて、`Service`を利用するクラスである`ServiceUser`を記述してみます。

```java
class ServiceUser {
    private final Service service;

    @Inject
    public ServiceUser(Service service) {
        this.service = service;
    }
    // serviceを利用したコードは省略...
}
```

具体的にどの`Service`を利用するかは、`ServiceUser`に現れていません。次はようやく、`ServiceUser`を使う例です。

```java
public class ServiceModule extends AbstractModule {
  @Override
  protected void configure() {
    bind(Service.class).to(RealService.class);
  }
}
```

```java
public static void main(String[] args) {
    Injector injector = Guice.createInjector(new ServiceModule());
    ServiceUser serviceUser = injector.getInstance(ServiceUser.class);
    // serviceUserを使ったコードは省略.....
}
```

Moduleを切り替えることで、依存する実装も切り替えることができるようになりました。

## ScalaでGuiceはどうなるのか
依存関係にGoogle Guice 4.0を追加します。

```scala
libraryDependencies += "com.google.inject" % "guice" % "4.0"
```

Scalaでの使い方としては、Javaとほとんど同じように書けます。`@Inject`の位置が、クラス名の後ろ、コンストラクタ引数の前になるという点に注意。

```scala
object TestDI {
  import javax.inject._
  import com.google.inject.AbstractModule

  trait Service {
    def doSomething(): Unit
  }

  class RealService extends Service {
    def doSomething() { println("This is RealService") }
  }

  class FakeService extends Service {
    def doSomething() { println("This is FakeService") }
  }

  class ServiceUser @Inject() (service: Service) {
    def use() { service.doSomething() }
  }

  class ServiceModule extends AbstractModule {
    override protected def configure() {
      bind(classOf[Service]).to(classOf[RealService])
    }
  }
}
```

使う時もJavaとほぼ同様です。

```scala
import com.google.inject._
val injector: Injector = Guice.createInjector(new ServiceModule)
val user: ServiceUser = injector.getInstance(classOf[ServiceUser])
user.use //=> "This is RealService"
```

## まとめ
Scalaでも、おおむねJavaと同じようにGuiceは使えることが分かりました……が、JavaのものをそのままScalaに移しても、あんまりScalaっぽくならないので微妙感が漂う気がします。なんかもうちょっとラップしたライブラリが欲しくなるなる……。

Playなどのフレームワークと統合した場合にGuiceはどういった使い勝手になるのかについては、今後調査したいですね……。

## 参考にしたもの
- https://github.com/google/guice/wiki/Motivation
- https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection