Personal tools
You are here: Home ブログ matsuyama Javaでdelegate
Document Actions

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も書けないしつらすぎる。

Category(s)
program
java
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/matsuyama/delegate_on_java/tbping

Re:Javaでdelegate

Posted by Anonymous User at 2006-09-23 15:25
Closureクラスをつくらなくても、final宣言する方法もあると思いますが、それではだめなんでしょうか?

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

Posted by matsuyama at 2006-09-23 20:14
finalの仕組みをいまいち理解していません。finalという名前から感覚的に避けた次第であります。たとえばclosure内でfinalな変数の値を変更したい場合はどうするのか、finalな変数はcontext dependに動作するのか、などです。実際、findIfを利用したメソッド

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で実装できるのか、という疑問があるのです。
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.