问题描述
我目前在一家拥有多种模块的公司工作。在那家公司里,如果你想提供通过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< ModuleXObject> loadAllObjects();
}
public interface ModuleYObjectRepository {
List< ModuleYObject> loadAllObjects();
}
public class ExternalObjectRepository implements ModuleXObjectRepository,ModuleYObjectRepository {
public List< ExternalObject> loadAllObjects(){
// ...
}
}
所以我的问题是,是否有可能实现这样的目标,以及如何实现?
我应该注意到,我尝试了一些不同的方法,我想包括它们的完整性并描绘它们的缺点(在我眼中)。
方法1 :
public interface ModuleXObjectRepository {
List<扩展ModuleXObject> loadAllObjects();
}
公共接口ModuleYObjectRepository {
列表< ;?扩展ModuleYObject> loadAllObjects();
}
public class ExternalObjectRepository implements ModuleXObjectRepository,ModuleYObjectRepository {
public List< ExternalObject> loadAllObjects(){
// ...
}
}
这种方法与我更喜欢的解决方案非常接近,但是会得到如下代码:
List< ;?扩展ModuleXObject> objects = repository.loadAllObjects();
因此,要求用户在每个List-Declaration中包含?extends loadAllObjects()。
方式2 :
public interface ModuleXObjectRepository {
List< ModuleXObject> loadAllObjects();
}
public interface ModuleYObjectRepository {
List< ModuleYObject> loadAllObjects();
$ b $ public class ExternalObjectRepository implements ModuleXObjectRepository,ModuleYObjectRepository {
public List loadAllObjects(){
// ...
}
}
这种方法只是省略了ExternalObjectRepository中的泛型,因此我认为这会降低类型安全性。此外,我还没有测试过,如果这实际上工作。
只是为了reharse,是否有任何可能的方式来定义loadAllObjects方法的方式,使用户能够获得使用各自模块的对象键入的列表,而不需要
允许将其输入为 List< ModuleXObject> 是其他代码可以保存为 List< ExternalObject> 。
全部 ExternalObject 实例是 ModuleXObject 实例,但反过来不是这样。
考虑下面的附加类:
public class MonkeyWrench implements ModuleXObject {
// STUFF
}
MonkeyWrench 实例不是 ExternalObject 个实例,但是如果可以将 List< ExternalObject> 转换为 List< ModuleXObject> 可能会向此集合添加 MonkeyWrench 实例,这会导致运行时类转换异常的风险,并且会破坏类型安全性。
$ b
for(ExternalObject externalObject:externalObjectRepository.loadAllObjects())
code>
如果其中一个实例是 MonkeyWrench 实例,则运行time class cast ,这是泛型意味着避免的。
的含义?扩展ModuleXObject 是您可以从集合中读取任何对象作为 ModuleXObject ,但不能向其他代码添加任何内容
在你的情况下,我建议使用?扩展ModuleXObject ,因为它的语义看起来与您想要的一致,即拉出 ModuleXObject 实例,例如
ModuleXObjectRepository repo = //获取回购但是
for(ModuleXObject obj:repo.loadAllObjects()){
//用obj $ b做东西$ b}
I'm currently working at a company that has a diverse set of modules. In that company if you want to provide module internals you provide it via a java interface, that hides the actual implementing type and gives an interface for the requesting module. Now I want to have one provider to be able to provide data for multiple modules that expose different fields or methods of the actual internal data.
Therefore I have an internal Object, which has some data and I have an interface for each module that needs access to some but not strictly all fields. Finally I have an external object that implements all those interfaces and holds an instance of the internal object to delegate the method calls:
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(); } }
Now that is all fine and dandy, but if I want to provide - lets say - repository methods for finding a list of said objects typed for the correct module, I run into problems with how I can achieve that. I would wish for something like the following:
public interface ModuleXObjectRepository { List<ModuleXObject> loadAllObjects(); } public interface ModuleYObjectRepository { List<ModuleYObject> loadAllObjects(); } public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository { public List<ExternalObject> loadAllObjects() { // ... } }
This doesn't compile saying the return type is incompatible.So my question is, if it is possible to achieve something like that and if, how?
I should note that I tried some different approaches which I want to include for completeness and to portray their downsides (in my eyes).
Approach 1:
public interface ModuleXObjectRepository { List<? extends ModuleXObject> loadAllObjects(); } public interface ModuleYObjectRepository { List<? extends ModuleYObject> loadAllObjects(); } public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository { public List<ExternalObject> loadAllObjects() { // ... } }
This approach is quite close to the solution I would prefer, but results in code like this:
List<? extends ModuleXObject> objects = repository.loadAllObjects();
Therefore requiring the user to include the "? extends" into each List-Declaration regarding to an invocation of loadAllObjects().
Approach 2:
public interface ModuleXObjectRepository { List<ModuleXObject> loadAllObjects(); } public interface ModuleYObjectRepository { List<ModuleYObject> loadAllObjects(); } public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository { public List loadAllObjects() { // ... } }
This approach just omits the generic in the ExternalObjectRepository and therefore reduces the type safety too much in my opinion. Also I haven't tested if this actually works.
Just to reharse, is there any possible way to define the loadAllObjects-method in a way that enables users to get lists that are typed with the objects for their respective module without
- requiring "? extends" in the users code
- degrading type safety in the repository implementation
- using class/interface level generics
The challenge with allowing it to be typed as List<ModuleXObject> is that other code may hold is as a List<ExternalObject>.
All ExternalObject instances are ModuleXObject instances but the inverse is not true.
Consider the following additional class:
public class MonkeyWrench implements ModuleXObject{ //STUFF }
MonkeyWrench instances are NOT ExternalObject instances but if one could cast a List<ExternalObject> to a List<ModuleXObject> one could add MonkeyWrench instances to this collection, and this causes a risk of run time class cast exceptions and ruins type safety.
Other code could very easily have:
for(ExternalObject externalObject:externalObjectRepository.loadAllObjects())
If one of those instances is a MonkeyWrench instance, run time class cast, which is what generics are meant to avoid.
The implication of ? extends ModuleXObject is that you can read any object from the collection as a ModuleXObject but you can't add anything to the collection as other code may have additional constraints on the collection that are not obvious/available at compile time.
I'd suggest in your case to use ? extends ModuleXObject as its semantics seem to align with what you want, namely pulling out ModuleXObject instances, e.g.
ModuleXObjectRepository repo = //get repo however for(ModuleXObject obj : repo.loadAllObjects()){ //do stuff with obj }
这篇关于List中的Java泛型返回从多个接口继承的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!