List中的Javagenerics返回从多个接口inheritance的方法的类型

我目前在一家拥有各种模块的公司工作。 在那家公司,如果你想提供模块内部,你可以通过java接口提供它,它隐藏了实际的实现类型,并为请求模块提供了一个接口。 现在我希望有一个提供程序能够为多个模块提供数据,这些模块公开了实际内部数据的不同字段或方法。

因此,我有一个内部对象,它有一些数据,我有一个接口,每个模块需要访问一些但不是严格的所有字段。 最后,我有一个外部对象,它实现了所有这些接口并保存了一个内部对象的实例来委托方法调用:

public class InternalObject { public int getA() { return 0; } public int getB() { return 0; } } public interface ModuleXObject { int getA(); } public interface ModuleYObject { int getA(); int getB(); } public class ExternalObject implements ModuleXObject, ModuleYObject { private InternalObject _internal; public int getA() { return _internal.getA(); } public int getB() { return _internal.getB(); } } 

现在这一切都很好,但是如果我想提供 – 让我们说 – 用于找到为正确模块键入的所述对象列表的存储库方法,我遇到了如何实现这一点的问题。 我希望得到以下内容:

 public interface ModuleXObjectRepository { List loadAllObjects(); } public interface ModuleYObjectRepository { List loadAllObjects(); } public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository { public List loadAllObjects() { // ... } } 

这不会编译说返回类型不兼容。 所以我的问题是,如果有可能实现类似的东西,如果,如何?


我应该注意到,我尝试了一些不同的方法,我想包括它们的完整性并描绘它们的缺点(在我看来)。

方法1

 public interface ModuleXObjectRepository { List loadAllObjects(); } public interface ModuleYObjectRepository { List loadAllObjects(); } public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository { public List loadAllObjects() { // ... } } 

这种方法与我希望的解决方案非常接近,但会产生如下代码:

 List objects = repository.loadAllObjects(); 

因此,要求用户在每个List-Declaration中包含有关loadAllObjects()调用的“?extends”。

方法2

 public interface ModuleXObjectRepository { List loadAllObjects(); } public interface ModuleYObjectRepository { List loadAllObjects(); } public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository { public List loadAllObjects() { // ... } } 

这种方法只省略了ExternalObjectRepository中的generics,因此在我看来太过于减少了类型安全性。 此外,我还没有测试这是否真的有效。


只是为了重新解析,是否有任何可能的方法来定义loadAllObjects方法,使用户能够获得使用各自模块的对象键入的列表,而无需

  • 在用户代码中要求“?extends”
  • 降低存储库实现中的类型安全性
  • 使用类/接口级generics

允许将其键入List的挑战是其他代码可以保存为List

所有ExternalObject实例都是ModuleXObject实例,但反之不是真。

考虑以下附加类:

 public class MonkeyWrench implements ModuleXObject{ //STUFF } 

MonkeyWrench实例不是ExternalObject实例,但如果可以将List List转换为List则可以将MonkeyWrench实例添加到此集合中,这会导致运行时类转换exception和MonkeyWrench类型安全的风险。

其他代码可以很容易地具有:

 for(ExternalObject externalObject:externalObjectRepository.loadAllObjects()) 

如果其中一个实例是MonkeyWrench实例,则运行时类转换,这是generics要避免的。

这意味着? extends ModuleXObject ? extends ModuleXObject是您可以从集合中读取任何对象作为ModuleXObject但您不能向集合添加任何内容,因为其他代码可能对集合的其他约束在编译时不明显/可用。

在你的情况下,我建议使用? extends ModuleXObject ? extends ModuleXObject因为它的语义似乎与你想要的一致,即拉出ModuleXObject实例,例如

 ModuleXObjectRepository repo = //get repo however for(ModuleXObject obj : repo.loadAllObjects()){ //do stuff with obj }