Javaにクロージャを
クロージャ(closure)とは、振舞そのものをカプセル化したもののことだ。SmalltalkやRubyなど、動的なオブジェクト指向プログラミング言語ではブロックとして親しまれている。メソッド抽出や、継承、委譲などの王道のオブジェクト指向テクニックでは再利用が難しいコードを、スマートに再利用できるのが大きな魅力だ(マーチン・ファウラーによるクロージャのエントリ)。
たとえば、ループの仕方は同じで、ループ中で呼び出すメソッドだけが異なるような以下のような処理は、割とよくある。こうしたコードは、ループ処理の部分だけ共通なので再利用したいのだが、再利用できそうでなかなかできなく、DRY(Don't Repeat Yourself)好きのプログラマとしては歯がゆい思いをする。
JavaのコアAPIか、Jakarta Commonsあたりで、汎用性のあるクロージャ用インタフェースを用意してくれれば、Javaでのクロージャ的再利用がもっと促進されるのだろうが。
ちなみに、ロッド・ジョンソンは『実践J2EEシステムデザイン』の中で、上記の手法を使ってJDBC接続部分のコードを再利用する方法を紹介している。DIコンテナSeasarのS2JDBCにある、SelectHandlerやUpdateHandlerなども、こうしたクロージャの設計方針で作られている。また、JUnit3.8.xでは、ユーザが定義したテストメソッドをフレームワークが呼び出すとき、このクロージャ的テクニックを使っている。そこで使われているインタフェースは、junit.framework.Protectableだ。
参考文献:
たとえば、ループの仕方は同じで、ループ中で呼び出すメソッドだけが異なるような以下のような処理は、割とよくある。こうしたコードは、ループ処理の部分だけ共通なので再利用したいのだが、再利用できそうでなかなかできなく、DRY(Don't Repeat Yourself)好きのプログラマとしては歯がゆい思いをする。
void doThis(MyLogic logic) {こういうとき、たとえばRubyだとブロックを使って以下のように再利用できる。
for (int i=0; i<100; i++) {
logic.executeThis();
}
}
void doThat(MyLogic logic) {
for (int i=0; i<100; i++) {
logic.executeThat();
}
}
# 再利用部分Javaでこのクロージャ(ブロック)の威力を享受するにはどうすればいいか。Javaは、Rubyのように言語機構としてのクロージャは備わっていない。そのため、クロージャ的再利用はできないと思いがちだが、実際はインタフェースと匿名オブジェクトを使うと同じことができる。
def do_loop(&block)
100.times do
block.call
end
end
logic = MyLogic.new
do_loop { logic.execute_this } # ここがブロック
do_loop { logic.execute_that } # ここがブロック
// クロージャのためのインタフェース静的言語であるJavaの面倒なところは、このICallbackHandlerインタフェースを用意しなければならないことだ。ここではprocess()メソッドは無引数だが、再利用したいコードのコンテキストに応じて、パラメータを追加する必要があることもある。したがって、クロージャを使う局面ごとにインタフェースが必要になってしまう。これは、ちょっと面倒だ。
interface ICallbackHandler {
void process();
}
// 再利用部分
void doLoop(ICallbackHandler handler) {
for (int i=0; i<100; i++) {
handler.process();
}
}
final MyLogic logic = new MyLogic();
doLoop(new ICallbackHandler() {
void process() { logic.executeThis(); }
});
doLoop(new ICallbackHandler() {
void process() { logic.executeThat(); }
});
JavaのコアAPIか、Jakarta Commonsあたりで、汎用性のあるクロージャ用インタフェースを用意してくれれば、Javaでのクロージャ的再利用がもっと促進されるのだろうが。
ちなみに、ロッド・ジョンソンは『実践J2EEシステムデザイン』の中で、上記の手法を使ってJDBC接続部分のコードを再利用する方法を紹介している。DIコンテナSeasarのS2JDBCにある、SelectHandlerやUpdateHandlerなども、こうしたクロージャの設計方針で作られている。また、JUnit3.8.xでは、ユーザが定義したテストメソッドをフレームワークが呼び出すとき、このクロージャ的テクニックを使っている。そこで使われているインタフェースは、junit.framework.Protectableだ。
参考文献:
- ロッド・ジョンソン
- 実践J2EEシステムデザイン