代码之家  ›  专栏  ›  技术社区  ›  Double M

是否有带类型参数的泛型(带泛型的泛型)?

  •  2
  • Double M  · 技术社区  · 6 年前

    我需要定义一个通用总线接口,它可以是 CommandBus QueryBus .

    public interface Bus {
    
        <T> T execute(BusRequest<T> request);
    
    }
    
    public interface BusRequest<T> {
    }
    

    上面的例子是可行的,但是我想替换 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”没有类型参数

    2 回复  |  直到 6 年前
        1
  •  1
  •   Daniel Pryden    6 年前

    不能用Java编译器理解的方式来表达这种类型的关系。但是你可以通过 BusRequest 类型知道类型 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> .

    为了解决这个问题,我们只需要介绍另一个(!)用于跟踪有效负载类型的类型参数。例如:

    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

        2
  •  1
  •   Tom Hawtin - tackline    6 年前

    Kind ?

    不,你需要斯卡拉(或哈斯克尔)来做这个。