我有以下情况。我有一些A类,它有B类对象列表。
类型B有两个属性X,Y为string类型,两个getter为getX()getY()。
我希望在A类中有一个方法,它从由给定的string值选择的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解决这个问题的通用方法吗?
答案 0 :(得分:4)
你可以有一个功能
B findElementByProperty(String prop, PropertyExtractor<B,String> propEx)
其中PropertyExtractor<B,P>
是指向B
返回类型P
的函数的泛型函数指针。
只是Java没有函数指针。所以PropertyExtractor<B,P>
可以是一个单一方法的接口,比如P getProperty(B obj)
,你当然需要两个实现(分别包含对getX
和getY
的调用)。
但是,您可以很容易地看到,这不会为您节省很多代码。相反。
答案 1 :(得分:2)
你可以通过Guava之类的东西来减少像这样的事情的代码大小,它提供类似于功能语言风格列表理解的东西。
您也可以通过定义界面
自行完成其中一些操作public interface Predicate<T> {
boolean apply(T obj);
}
然后使用它创建一个finder方法:
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 :(得分: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;
}