Dependency Injectionでやりたいことはモジュールimport

Dependency Injection(DI)、最近のフレームワークには欠かせない気がする機能になってますね。
そしてDIの説明をみると「依存性の注入」みたいなことが書いてあって、ようわからんになりがちです。
実態としては高機能なimportなので、あまり難しいことを考えなくていいような気がします。

たとえば、こんな感じのMyServiceクラスがあってDIコンテナに管理させるとします。

@Component
class MyService {
  void method() {
  }
}

そして、MyServiceを使うMyControllerがあるとします。

@Component
class MyController {
  @Inject
  MyService service;

  void hello() {
    service.method();
  }
}

これって、実際のところMyServicemethod()がstaticであれば単にimportでいいわけです。

class MyService {
  static voic method() {
  }
}

のようにして、こう。

import MyService as service;
class MyController {
  void hello() {
    service.method();
  }
}

ただし、Javaのimportでは別名はつけれないので、こう。

import MyService;
class MyController {
  void hello() {
    MyService.method();
  }
}

実際、「staticキモチワルイ」を解消するくらいの気持ちで使ってることも多いです。

ただ、Javaの場合は先ほどの別名も含めて、いろいろ言語機能が足りていないのでDIというトリックで不足分を解決している、という感じになっています。 不足しているものとしてあげられるのが次のようなものになります。

  • 動的スコープ
  • AOP
  • テスト時のモック化
  • 設定外部化
  • 別名

動的スコープは、requestだとかsessionだとかでオブジェクトの寿命を指定する機能です。
これはこれでThreadLocalをいい感じに隠蔽する機能でもありますね。

AOPは、トランザクションとかロギングとかをメソッドに噛ませる機能ですね。「オブジェクト指向の次はアスペクト指向じゃー!」って盛り上がって、言語機能として使えるAspectJとかが一瞬流行ったことがあるけど、結局トランザクションとロギングくらいしか使いどころがないことがわかって、表だって話題に出ることはなくなりました・・・

あと、テスト時のモック化。
テストのときにDBやらファイルやらネットにアクセスしてられないということで、実装を入れ替えることができますね。
ただ、これはクラスローダーの問題なので、staticにして実装を入れ替えることは可能といえば可能。

ついでに設定外部化。
DIするついでに、いろんな値を設定から持ってこれるようになってますね。

あとは別名。やってもよさそうなのだけど、現実みんなSpring使ってて代替されてるのと、パターンマッチングなんかの機能の実装で忙しそうなので、いまのところは気配なしですね。言語機能おちついたらやるかも、という期待をしている。

という感じで、言語機能がそれなりに整えばDIは不要にできるものです。AOPAspectJで実現できるように。
「依存性の注入」みたいなことがやりたいわけではなく、付随する便利さのために使うものですね。
オブジェクト指向とセットで説明されることも多いけど、言語機能の不足をオブジェクト機能+いろんなハックで解決してるというものでもあります。

そういえばWEB+DB PRESS vol.132の特集にもそういう話を書いたのだった。