我有通用结构,我需要使用各种泛型类型的属性进行搜索。
让我们考虑以下实施:
public class Person {
private int id;
private String name;
// + getters & setters
}
现在我有自定义数据结构,其中一种方法就像:
public T search(T data) { ... }
这当然是无稽之谈。我在代码中真正需要的是:
Person p = structure.search(12); // person's id
或
Person p = structure.search("Chuck N."); // person's name
所以在pseudoJava(:)中,代码将是这样的:
public T search(T.field key)
这当然是不可能的:(但是如何处理这种情况呢?重点是:我不想强迫客户的类(如Person)实现我自己的界面或扩展我自己的有没有解决办法?
答案 0 :(得分:2)
您可以通过添加Class参数使搜索签名包含type参数。举个例子:
//replace 'id' with whatever your identifier types are
public <T> T search(int id, Class<T> entityClass) { ... }
客户必须使用像
这样的方法Person p = foo.search(123, Person.class);
NotAPerson n = foo.search(234, NotAPerson.class);
包括课程可能看起来有点难看,但是当你真正考虑事情时 - 客户是否总是知道它在寻找什么?并且search()
背后的代码不需要知道要搜索的类型 - 如果您有不同类型共享的ID会怎么样?
如果您的ID不是一致的类型,则可以将签名更改为
public <T> T search(Serializable id, Class<T> entityClass) { ... }
答案 1 :(得分:2)
看起来你想要某种中间策略对象,它提取一个值,比较一个值,或许提供一个哈希码或一个比较函数。
类似的东西:
interface Matcher<T> {
boolean matches(T obj);
}
或方法如:
boolean matches(T obj, V value);
V get(T obj);
int hash(T obj);
int compare(T a, T b);
使用当前的Java语法有点冗长(可能会因JDK 8而改变)。
你最终会得到这样的东西:
Person p = structure.search(
new Matcher<Person>() { public boolean matches(Person person) {
return person.getID() == 12;
})
);
或:
Person p = structure.search(
new Matcher<Person,Integer>() {
public boolean matches(Person person, Integer id) {
return person.getID() == id;
}
),
12
);
在JDK8中,可能类似于:
Person p = structure.search(
{ Person person -> person.getID() == 12 }
);
或:
Person p = structure.search(
{ Person person, Integer id -> person.getID() == id },
12
);
或:
Person p = structure.search(
{ Person person -> person.getID() },
12
);
或:
Person p = structure.search(
Person#getID, 12
);
答案 2 :(得分:0)
我建议您使用Comparable接口。
Person p = structure.searchUnique(new FieldFilter(“id”,12)); //搜索ID为12的人 Person [] p = structure.searchAll(new FieldFilter(“name”,“John”)); //搜索名为John的人
此外,我们可以实现允许搜索目标类的所有可用字段的过滤器:
Person [] p = structure.searchAll(new FieldFilter(“John”)); //搜索所有约翰斯
如何实现?以下是一些提示。
首先是“结构”是什么?它是一个包装集合,可能在将来可能包含一些索引功能。这个类应该有像
这样的构造函数结构(收集数据);
它的搜索方法迭代给定的集合并调用实现Comparable的FieldFilter的compateTo()方法:
for(T elem:collection){ if(filter.compareTo(elem)){ result.add(ELEM); } } 返回结果;
FieldFilter应如下所示:
公共类FieldFilter实现Comparable { private String fieldName; 私人V fieldValue; public FieldFilter(String fieldName,V fieldValue){ this.fieldName = fieldName; this.fieldValue = fieldValue; } public boolean compareTo(T elem){ Field field = elem.getClass()。getField(fieldName); field.setAccessible(真); return field.getValue()。equals(fieldValue); } }
请注意,代码是直接以答案形式编写的,从未编译过,因此无法按原样使用。但我希望它能描述这个想法。
答案 3 :(得分:0)
如果要在搜索的类型和传递给search()方法的参数类型之间通过泛型强制执行映射,则必须在某处指定。如果没有至少一个用于客户端类的通用标记接口,我认为没有办法做到这一点。
这样的东西会起作用:
public interface Searchable<T> { }
public class Person implements Searchable<String> {
// ...
}
public <T extends Searchable<K>, K> T search(K key) {
// ...
}
现在编译器将允许:
Person p = search("John Doe");
但不是:
Person p = search(5);
如果连标记界面都不是一个选项,我担心您最好的选择是使用基于参数类型的特定搜索方法,如:
public <T> T searchByInt(int key) {
// ...
}
public <T> T searchByString(String key) {
// ...
}
但当然这意味着无效的案例,如
Person p = searchByInt(5);
不会在编译时捕获,而是需要在运行时检查。