我们方法的目标是为我们现有的DAO和模型类引入接口。模型类由各种类型的资源ID标识,资源ID不仅是随机数,而且还具有语义和行为。因此,我们必须通过对象而不是原始类型来表示资源ID。
资源ID的当前方法:
interface ResourceId<T> {
T get();
}
class UserId implements ResourceId<String> {
public String get();
}
我们资源/模型的当前方法:
interface Resource<I extends ResourceId> {
I id();
}
class User implements Resource<UserId> {
public UserId id();
}
我正在努力为我们的DAO class 寻找一个可行的解决方案。这是我尝试但失败的一些方法:
===选项1 ===
失败:
error: > expected
Java中似乎禁止多个级别的泛型类型interface Dao<R extends Resource<I extends ResourceId>> {
R findById(I id);
void save(R u);
}
class UserDao implements Dao<User> {
public User findById(UserId id);
public void save(User u);
}
===选项2 ===
失败:
UserDao is not abstract and does not override abstract method <R>save(R) in Dao
Dao 看起来也很愚蠢。 UserDao应该是Dao 对象。interface Dao<I extends ResourceId> {
<R extends Resource<I>> R findById(I id);
<R extends Resource<I>> void save(R u);
}
class UserDao implements Dao<UserId> {
public User findById(UserId id);
public void save(User u);
}
===选项3 ===
失败:
UserDao is not abstract and does not override abstract method <I>findById(I) in Dao
即使有效,我也不受R实际实现的ResourceId的束缚。interface Dao<R extends Resource> {
<I extends ResourceId> R findById(I id);
void save(R u);
}
class UserDao implements Dao<User> {
public User findById(UserId id);
public void save(User u);
}
===选项4 ===
编译。
但是,UserDao中的#findById必须采用ResourceId类型的通用参数,而不是UserId。同样,在#findById的实现内部,我们必须将#get()的结果强制转换为String。
通常,问题是ResourceId的类型不受R实际实现的ResourceId约束。
interface Dao<R extends Resource> {
R findById(ResourceId id);
void save(R u);
}
class UserDao implements Dao<User> {
public User findById(ResourceId id);
public void save(User u);
}
===选项5 ===
编译。
但是Dao 看起来很愚蠢。我们要使用哪个ResourceId(即UserId)的信息在资源(即User)的实现中已经可用。有没有更清洁的方法?
interface Dao<R extends Resource, I extends ResourceId> {
R findById(I id);
void save(R u);
}
class UserDao implements Dao<User, UserId> {
public User findById(UserId id);
public void save(User u);
}
任何想法如何正确解决这个问题?
最佳答案
通过适当调整,您的选项1可以正常工作。首先将ResourceId
通用类型规范添加到Dao
声明中:
static interface Dao<I extends ResourceId<?>, R extends Resource<I>> {
R findById(I id);
void save(R u);
}
...,然后对
Dao
子类执行相同的操作: static class UserDao implements Dao<UserId, User> {
public User findById(UserId id) { return null; }
public void save(User u) {}
}
由于您不需要知道
ResourceId
类的上下文中<T>
(Resource
)的通用类型是什么,您可以在此处使用通配符将其关闭: static interface Resource<I extends ResourceId<?>> {
I id();
}
最后,完整的代码将编译为:
public class NestedGenerics {
static interface ResourceId<T> {
T get();
}
static class UserId implements ResourceId<String> {
public String get() { return null; }
}
static interface Resource<I extends ResourceId<?>> {
I id();
}
static class User implements Resource<UserId> {
public UserId id() { return null; }
}
static interface Dao<I extends ResourceId<?>, R extends Resource<I>> {
R findById(I id);
void save(R u);
}
static class UserDao implements Dao<UserId, User> {
public User findById(UserId id) { return null; }
public void save(User u) {}
}
}
Complete code on GitHub
希望这可以帮助。