1


我有以下情况。我有一些 A 类,它有 B 类型的对象列表。B 类型有两个属性 X,字符串类型的 Y 和两个 getter getX() getY()。我想在 A 类中有一个方法,它从给定字符串值选择的 B 对象集合中返回一个对象。例如:

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

对于另一个属性 Y,我将有几乎相同的代码,btu 而不是 getX(),将有 getY()。对我来说,这是不必要的代码冗余。我的问题是:如何编写此方法以便通过 X 或 Y 属性值找到一种方法?这是用Java解决这个问题的通用方法吗?

4

3 回答 3

4

你可以有一个功能

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

where是指向返回类型PropertyExtractor<B,P> 函数的泛型函数指针。BP

只是Java没有函数指针。因此PropertyExtractor<B,P>,可以改为具有单个方法的接口,例如P getProperty(B obj),您当然需要两个实现(分别包装对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));
}

如果您只处理两个属性,所有这些策略都可能会增加而不是减少代码大小。优势只会在更大的范围内出现,并且您可能会付出代价,使不熟悉函数式样式和/或反射的人的代码可读性降低。

于 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 回答