java泛型方法继承,List中的Java泛型返回从多个接口继承的方法

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 loadAllObjects();

}

public interface ModuleYObjectRepository {

List loadAllObjects();

}

public class ExternalObjectRepository implements ModuleXObjectRepository, ModuleYObjectRepository {

public List 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 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 loadAllObjects();

}

public interface ModuleYObjectRepository {

List 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 is that other code may hold is as a List.

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 to a List 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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值