私は興味深い状況があり、これを行うより良い方法があるのだろうかと思っています。状況はこれです、私は木構造(具体的には抽象構文木)を持っていて、いくつかのノードは様々な型の子ノードを含むことができますが、すべては与えられた基底クラスから拡張されています。 タイプの安全性、Javaのジェネリックとクエリ
は、私は頻繁にこの木にクエリをしたいと私は私が興味の特定のサブタイプを取り戻すしたいと思います。だから私は、私は、その後、一般的なクエリメソッドに渡すことができ述語クラスを作成しました。public <T extends Element> List<T> findAll(IElementPredicate pred, Class<T> c);
Class
引数は単に戻り値の型を示すために使用されました。最初は私はこのように見えたクエリメソッドを持っていました。このアプローチについて私を困らせたのは、私の述語はすべてすでに特定のタイプのものだったので、ここには冗長な情報があるということです。だから私はこのようにそれをリファクタリング
List<Declaration> decls =
scope.findAll(new DeclarationPredicate(), Declaration.class);
:
public <T extends Element> List<T> findAll(IElementPredicate<T> pred);
をIElementPredicate
インターフェースは次のようになりますここで、
public interface IElementPredicate<T extends Element> {
public boolean match(T e);
public String getDescription();
public Class<T> getGenericClass();
}
ここでのポイントは、述語ということである典型的なコールは、次のようになります代わりにClass
オブジェクトを提供するようにインターフェイスが拡張されました。これは、実際のfindAll
メソッドを少し書くだけで、述語を書くのにもう少し作業が追加されますが、それらは本質的に小さな「1回限りの」ものであり、そうしないとクエリーコールがとてもうまくなります。余分な(潜在的に冗長な)引数を追加する必要があります。
List<Declaration> decls = scope.findAll(new DeclarationPredicate());
私は以前にこのパターンに気付きませんでした。これはJavaジェネリックのセマンティクスを扱う典型的な方法ですか?私はいくつかのより良いパターンが欠けている場合はちょうど好奇心。
コミッション?
UPDATE:あなたは、クラスを何が必要なのですかた
一つの疑問?ここでのfindAllの実装です:
public <T extends Element> List<T> findAll(IElementPredicate<T> pred) {
List<T> ret = new LinkedList<T>();
Class<T> c = pred.getGenericClass();
for(Element e: elements) {
if (!c.isInstance(e)) continue;
T obj = c.cast(e);
if (pred.match(obj)) {
ret.add(c.cast(e));
}
}
return ret;
}
試合だけTを取ることは事実ですが、私はそれを呼び出すことができます前に、オブジェクトがTであることを確認する必要があります。そのためには、クラスの "isInstance"メソッドと "cast"メソッドが必要です(私が知る限り)。
私は訪問者を頻繁に使用していますが(この非常に同じプロジェクトでは、実際には)、この特定のケースでは、訪問者パターンは、必要と思われるよりもはるかに多くのコードと複雑さを追加します。 –
私はあなたに同意する、それは大きな副作用がある方法でcomplicatorsスイッチのようなものです。あなたが望むように一般性を逆転するのは難しいです。私はあなたの解決策がベストであると信じています。なぜなら、ビジターがなければ、レイトバインドや明示的な型チェックが必要になるからです。あなたのソリューションは、実装者にその負担をかけるのではなく型チェックを集中させるので、より優れています。この問題は、汎用のComparable実装でも同様です。 –
そして、レイトバインディングでは、Javaは参照型ではなく、オブジェクト型に基づいてオーバーロードされたメソッド解決を実装する必要があることを意味しました。これは基本的にコードで実装したものです。 –