1


次のような状況があります。タイプ B のオブジェクトのリストを持つクラス A があります。タイプ B には、文字列型の 2 つのプロパティ X、Y と 2 つのゲッター getX() getY() があります。指定された文字列の値によって選択された B オブジェクトのコレクションからオブジェクトを返すようなクラス A のメソッドが必要です。例えば:

B findElementByX(String x) {
    for (B i : list) {
         if (i.getX().equals(x)
             return i;
    }
    return null;
}

他のプロパティ Y i のコードはほとんど同じで、getX() の代わりに getY() があります。私にとっては、不要なコードの冗長性です。私の質問は、X または Y プロパティ値で検索するメソッドを 1 つ持つために、このメソッドをどのように記述するかということです。これはJavaでこれを解決する一般的な方法ですか?

4

3 に答える 3

4

あなたは機能を持つことができます

B findElementByProperty(String prop, PropertyExtractor<B,String> propEx)

ここで、は型 を返すPropertyExtractor<B,P> 関数への汎用関数ポインタです。BP

Javaには関数ポインタがありません。PropertyExtractor<B,P>代わりに、単一のメソッドを持つインターフェイスにすることもできます。たとえば、P getProperty(B obj)その場合、もちろん 2 つの実装が必要になります (それぞれgetXとの呼び出しをラップしますgetY)。

ただし、これによって多くのコード行が節約されないことは容易にわかります。それとは反対に。

于 2012-11-18T14:09:03.277 に答える
2

関数型言語スタイルのリスト内包表記に似たものを提供するGuavaのようなものを使用することで、このようなもののコードサイズを減らすことができます。

インターフェイスを定義することにより、これの一部を自分でロールすることもできます

public interface Predicate<T> {
    boolean apply(T obj);
}

それを使用してファインダーメソッドを作成します。

B findElementByPredicate(Predicate<B> predicate) {
    for (B b : list) {
        if (predicate.apply(b))
            return b;
    }
    return null;
}

(コメントに記載されているように)リフレクションを使用してフィールドの値を取得することもできます。arne.bの回答で定義されたインターフェースを実装すると、定義できます

public class ReflectivePropertyExtractor<T, P> implements PropertyExtractor<T, P> {

    String fieldName;

    public ReflectivePropertyExtractor(String fieldName) {
        this.fieldName = fieldName;
    }

    @Override
    public P getProperty(T obj) {
        try {
            Method m = B.class.getMethod(makeAccessorName());
            return (P) m.invoke(obj);
        } catch (InvocationTargetException e) {
            return null;
        } catch (NoSuchMethodException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    private String makeAccessorName() {
        return "get" + capitalize(fieldName);
    }

    private String capitalize(String s) {
        if ((s == null) || (s.length() == 0))
            return s;
        return s.substring(0, 1).toUpperCase() + s.substring(1);
    }

}

指定されたフィールド名に対して機能するプロパティエクストラクタを作成し、彼が回答で説明したようにそれを使用するか、それに基づいて述語を作成します。

public class PropertyMatchPredicate<T, P> implements Predicate<T> {
    private final P matchValue;
    private final PropertyExtractor<T, P> extractor;

    public PropertyMatchPredicate(P matchValue, PropertyExtractor<T, P> extractor) {
        this.matchValue = matchValue;
        this.extractor = extractor;
    }

    @Override
    public boolean apply(T obj) {
        return matchValue.equals(extractor.getProperty(obj));
    }
}

そして、その述語をfindByPredicate上記で使用します。

B findElementByProperty(String matchField, final String matchValue) {
    final ReflectivePropertyExtractor<B, String> extractor = new ReflectivePropertyExtractor<B, String>(matchField);
    return findElementByPredicate(new PropertyMatchPredicate<B, String>(matchValue, extractor));
}

2 つのプロパティのみを扱っている場合、これらの戦術はすべて、コード サイズを縮小するのではなく、増加させる可能性があります。利点はより大きな規模でのみ発生し、機能スタイルやリフレクションに慣れていない人にとってコードが読みにくくなるという代償を払う可能性があります。

于 2012-11-18T20:52:12.060 に答える
1

X または Y を別のパラメーターとして渡して、getX() または getY() を検索します。それ以外の場合は null を返します。

B findElementByXY(String s,String identifier) {
    for (X i : list)
    {
         if ("X".equals(identifier)&&i.getX().equals(s))
             return i;
         else if ("Y".equals(identifier)&&i.getY().equals(s))
             return i;

    }
    return null;
}
于 2012-11-18T14:04:25.117 に答える