Javaでdelegate
grep -iv lru_languages java が空文字列で悲しいですこんにちは。先日javaではinterfaceを一々定義しないとdelegateが使えないという衝撃的な事実を知りました。理論的には言語レベルで適切な変換をかければ互換性を保ちつつC#のdelegateのような書き方ができるはずなんだけどと脳内で愚痴りつつ対策を考えてみました。もちろん僕は必要になるごとにinterfaceをちまちま書くような丁寧なプログラマではないので、汎用的に使えるdelegate interfaceを実装することになります。それで出来上がったのが以下。
Delegate.java:
public interface Delegate<T, R> { public R invoke(T arg); }
言語的に適切にマングリングかければ互換性を保持しつつC++みたいなtemplate汎用性を実現できるのになと脳内で愚痴りながら、2引数版。
Delegate2.java:
public interface Delegate2<T1, T2, R> { public R invoke(T1 arg1, T2 arg2); }
それでたとえばC++でいうfind_ifをリストコンテナに書く場合は、
public Foo[] findIf(Delegate<Foo, Boolean> pred) { List<Foo> result = new ArrayList<Foo>(); for (Foo child: children) { if (pred.invoke(child)) { result.add(child); } } return (Foo[])result.toArray(new Foo[0]); }
となります。使うには、
MyList list = ...; Foo[] found = list.findIf(new Delegate<Foo, Boolean>() { public Boolean invoke(Foo f) { return f.name.equals("Bar"); } });
です。ただdelegate内部で外部変数を使いたいというときに、この方法では独自にクラスを定義しなくてはいけないので面倒です(というか本末転倒)。ということで以下のようにClosureを定義します。
Closure.java:
public abstract class Closure<D, T, R> implements Delegate<T, R> { protected D data; public Closure(D data) { this.data = data; } public abstract R invoke(T arg); }
Closure2.java:
public abstract class Closure2<D, T1, T2, R> implements Delegate2<T1, T2, R> { protected D data; public Closure(D data) { this.data = data; } public abstract R invoke(T1 arg1, T2 arg2); }
これでたとえば先のfindIfの例だと、
MyList list = ...; String name = "Bar"; Foo[] found = list.findIf(new Closure<String, Foo, Boolean>(name) { public Boolean invoke(Foo f) { return f.name.equals(data); } });
といった具合に書けるのです。ちなみに標準でこういうinterfaceが含まれているかもしれないと1.4(Tigerじゃないと駄目?)内を探してみましたが、無いようです。以前どこかで見たような気がするんですが。まあいいでしょう。javaもそろそろtemplate overloadingあるいはdefault template valueをサポートしてくれないかな、無いとtupleも書けないしつらすぎる。
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/matsuyama/delegate_on_java/tbping
Re:Javaでdelegate
MyList list = ...;
final String name = "Bar";
final int age = 19;
Foo[] found = list.findIf(new Delegate
public Boolean invoke(Foo f) {
return f.name.equals(name) && (f.age == age);
}
});
delegate内部で外部のオブジェクトを複数利用したいときdataとなるクラス(パラメータークラス)を新しくつくるのも本末転倒です。
まず匿名クラスをつくる時点でかなりその処理コンテキストに依存してることは明白なので、外部データ用にテンプレートで対処しておくというのはあまり意味が無い気がします。
それよりfinalしてしまったほうが便利な気がするのですが、何か他の理由があるんでしょうか?
Re:Javaでdelegate
public Foo getFoo(String name) {
return findIf(new Closure<String, Boolean, Foo>(name) {
public Boolean invoke(Foo f) {
return f.name.equals(data);
}
})[0];
}
を定義したい場合にfinalで実装できるのか、という疑問があるのです。