Существуют ли дженерики с параметрами типа (дженерики с дженериками)? - PullRequest
0 голосов
/ 21 октября 2018

Мне нужно определить общий интерфейс шины, который может быть 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' не имеет параметров типа

Ответы [ 2 ]

0 голосов
/ 21 октября 2018

Вы не можете выразить это отношение типа способом, понятным компилятору 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>.

Чтобы решить эту проблему, нам просто нужно ввести другой (!) Параметр типа, чтобы отслеживать тип полезной нагрузки.Например:

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

0 голосов
/ 21 октября 2018

A Вид ?

Нет.Для этого вам понадобится Scala (или Haskell).

...