是否有带有类型参数的泛型(带有泛型的泛型)? [英] Are there generics with type parameters (generics with generics)?

查看:498
本文介绍了是否有带有类型参数的泛型(带有泛型的泛型)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要定义一个通用总线接口,该接口可以是CommandBusQueryBus.

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);
}

演示: https://ideone.com/U1TLXr

但是,为了更加有用,您可能需要在每个请求对象中提供一些总线特定的有效负载信息.这样一来,每种请求类型都与总线类型相关联,但是总线无法从请求对象中提取特定于总线的数据,因为例如可能存在多个实现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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆