しばらく前に、GoogleのDIコンテナであるGoogle Guiceを紹介するプレゼンテーションがGoogle Videoで公開された。
はじまって3分ほどのところに、「A Problem」として、Javaでstaticを使うことに対する次のような指摘がある。
Using static references comes with big problems!
- Tight coupling: depending on implementation, not interface
- Not polymorphic! Not OO!
- It's extremely global (no scoping)
- Leads to "all-or-nothing" testing
- And it's viral! It gives you "static cling!"
そうなんだよねぇー。特に最後がデカい。staticは伝染しちゃうんだよね。たとえばstaticなメソッドは、そこからさらにstaticに呼べるメソッドやstaticに参照/取得できるオブジェクトを要求してしまう。そうすると、その他の4つの問題とともにstaticな空気が広がっていく。
staticを使いたくなるのは、アプリケーションの設計において、論理的に離れたところから何らかのオブジェクトやメソッドを共に参照したくなった時が多い。何とか共用する部分だけを切り出しても「じゃあどうやってそこへの参照を得るのさ?」となった時に、お手軽に解決する道のひとつが「static」だ。いつでも、どこからでも参照できれば、そりゃあ、とりあえずは解決するよね。
単純なユーティリティメソッド程度ならそれでいいかもしれないけど、アプリケーションのロジックをstaticに実装したまま進めてしまうと、さっきのような問題が出てくる。「いつでも、どこからでも参照できる」ということは、いつでもどこでも、そこ「しか」参照できないということでもある。結合度が高くて単体テストも書きにくいし、変更するときも多態性が使えないから、謎のフラグで動作を微妙にコントロールしなくちゃいけなくなったりと、だんだんと醜悪なコードになってくる。醜悪なコードがあると気分や機嫌が悪くなってしまう。いやー、困ったもんだ。
そこで、GuiceのようなDIコンテナを使って、staticを使わずに必要なオブジェクトへの参照を得るわけだ。DIコンテナに登録しておけば、もともとの設計上は遠い位置にあっても、双方にとって妥当なインタフェースを定義して、同一のオブジェクトのメソッド呼び出すようなことが簡単にできる。気分も機嫌も良くなってめでたしめでたし(僕はGuiceじゃなくてPicoContainerを使っているけどね)。
というわけで、staticはいろいろと害があるから、アプリケーションの主要ロジックをサポートする単純なユーティリティメソッドや定数のみとするのが望ましい。そういった設計を実現するために、DIコンテナが有効なツールとなる。
オブジェクト指向プログラミングが良くないということであれば、staticを使いまくりでもいいと思うけど、その議論はまた別。