是否有带有类型参数的泛型(带有泛型的泛型)? [英] Are there generics with type parameters (generics with generics)?
问题描述
我需要定义一个通用总线接口,该接口可以是CommandBus
或QueryBus
.
public interface Bus {
<T> T execute(BusRequest<T> request);
}
public interface BusRequest<T> {
}
上面的示例有效,但我想用另一个扩展BusRequest
的泛型替换BusRequest
,以便您可以执行以下操作:
public interface CommandBus extends Bus<Command> {
// Inherited method would turn into something like
// <T> T execute(Command<T> cmd);
}
public interface Command<T> extends BusRequest<T> {
}
我将如何定义Bus
接口来做到这一点?用Java可以吗?
我尝试过:
public interface Bus<R extends BusRequest> {
<T> T execute(R<T> request);
}
但是它说:
类型'R'没有类型参数
您不能以Java编译器可以理解的方式来表达这种类型关系.但是,通过让BusRequest
类型知道应该使用的Bus
类型,并让Bus
知道它是哪种总线,您可以得到类似的效果.
例如:
// B is the type of the Bus subclass
public interface Bus<B extends Bus<B>> {
// R is the response type, and Q is the request type
<R, Q extends BusRequest<R, B>> R execute(Q request);
}
// a request is parameterized by R, the response type, and B, the bus type
public interface BusRequest<R, B extends Bus<B>> {}
// A CommandBus is a Bus for CommandBusRequests
public static class CommandBus implements Bus<CommandBus> {
@Override
public <R, Q extends BusRequest<R, CommandBus>> R execute(Q request) {
System.out.println("Got request of type: " + request.getClass());
return null;
}
}
public interface CommandBusRequest<T> extends BusRequest<T, CommandBus> {}
// StringCommandBusRequest is a BusRequest for a CommandBus that requests
// a response of type String
public static class StringCommandBusRequest
implements CommandBusRequest<String> {}
这些类型全部进行编译和类型检查,结果看起来像我想的那样:
public static void main(String[] args) throws Exception {
StringCommandBusRequest request = new StringCommandBusRequest();
Bus<CommandBus> bus = new CommandBus();
String result = bus.execute(request);
}
但是,为了更加有用,您可能需要在每个请求对象中提供一些总线特定的有效负载信息.这样一来,每种请求类型都与总线类型相关联,但是总线无法从请求对象中提取特定于总线的数据,因为例如可能存在多个实现BusRequest<?, CommandBus>
的类.>
要解决此问题,我们只需要引入another(!)类型参数来跟踪有效负载类型.例如:
public interface Bus<P, B extends Bus<P, B>> {
<R, Q extends BusRequest<R, P, B>> R execute(Q request);
}
public interface BusRequest<R, P, B extends Bus<P, B>> {
P getPayload();
}
public static class CommandBus
implements Bus<CommandBusRequestPayload, CommandBus> {
@Override
public <R, Q extends BusRequest<R, CommandBusRequestPayload, CommandBus>>
R execute(Q request) {
CommandBusRequestPayload payload = request.getPayload();
System.out.println("Got payload: " + payload);
return null;
}
}
public static abstract class CommandBusRequest<T>
implements BusRequest<T, CommandBusRequestPayload, CommandBus> {
@Override
public CommandBusRequestPayload getPayload() {
return new CommandBusRequestPayload();
}
}
public static class CommandBusRequestPayload {}
public static class StringCommandBusRequest
extends CommandBusRequest<String> {}
带有有效负载的演示: https://ideone.com/2aUwMW
I need to define a generic Bus interface that can either be a CommandBus
or QueryBus
.
public interface Bus {
<T> T execute(BusRequest<T> request);
}
public interface BusRequest<T> {
}
The above example works, but I'll want to replace BusRequest
by another generic that will extend BusRequest
, so that you could do the following:
public interface CommandBus extends Bus<Command> {
// Inherited method would turn into something like
// <T> T execute(Command<T> cmd);
}
public interface Command<T> extends BusRequest<T> {
}
How would I define the Bus
interface to do that? Is it possible in Java?
I have tried:
public interface Bus<R extends BusRequest> {
<T> T execute(R<T> request);
}
However it says:
Type 'R' does not have type parameters
You can't express this type relationship in a way the Java compiler will understand. But you could get a similar effect by making BusRequest
types know about the type of Bus
they're supposed to be used with, and by making Bus
know what type of Bus it is.
For example:
// B is the type of the Bus subclass
public interface Bus<B extends Bus<B>> {
// R is the response type, and Q is the request type
<R, Q extends BusRequest<R, B>> R execute(Q request);
}
// a request is parameterized by R, the response type, and B, the bus type
public interface BusRequest<R, B extends Bus<B>> {}
// A CommandBus is a Bus for CommandBusRequests
public static class CommandBus implements Bus<CommandBus> {
@Override
public <R, Q extends BusRequest<R, CommandBus>> R execute(Q request) {
System.out.println("Got request of type: " + request.getClass());
return null;
}
}
public interface CommandBusRequest<T> extends BusRequest<T, CommandBus> {}
// StringCommandBusRequest is a BusRequest for a CommandBus that requests
// a response of type String
public static class StringCommandBusRequest
implements CommandBusRequest<String> {}
These types all compile and type check, and the result looks like what I think you want:
public static void main(String[] args) throws Exception {
StringCommandBusRequest request = new StringCommandBusRequest();
Bus<CommandBus> bus = new CommandBus();
String result = bus.execute(request);
}
Demo: https://ideone.com/U1TLXr
To be more useful, however, you'll probably need some bus-specific payload information in each request object. As this stands, each request type is tied to a bus type, but the bus isn't able to extract bus-specific data from the request object, because for example there could be more than one class that implements BusRequest<?, CommandBus>
.
To solve this, we just need to introduce another(!) type parameter to keep track of the payload type. For example:
public interface Bus<P, B extends Bus<P, B>> {
<R, Q extends BusRequest<R, P, B>> R execute(Q request);
}
public interface BusRequest<R, P, B extends Bus<P, B>> {
P getPayload();
}
public static class CommandBus
implements Bus<CommandBusRequestPayload, CommandBus> {
@Override
public <R, Q extends BusRequest<R, CommandBusRequestPayload, CommandBus>>
R execute(Q request) {
CommandBusRequestPayload payload = request.getPayload();
System.out.println("Got payload: " + payload);
return null;
}
}
public static abstract class CommandBusRequest<T>
implements BusRequest<T, CommandBusRequestPayload, CommandBus> {
@Override
public CommandBusRequestPayload getPayload() {
return new CommandBusRequestPayload();
}
}
public static class CommandBusRequestPayload {}
public static class StringCommandBusRequest
extends CommandBusRequest<String> {}
Demo with payload: https://ideone.com/2aUwMW
这篇关于是否有带有类型参数的泛型(带有泛型的泛型)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!