Создание круговых общих ссылок
Я пишу приложение для выполнения некоторых распределенных вычислений в одноранговой сети. При определении сети у меня есть два класса P2PNetwork и P2PClient. Я хочу, чтобы они были универсальными, и поэтому имеют следующие определения:
P2PNetwork<T extends P2PClient<? extends P2PNetwork<T>>>
P2PClient<T extends P2PNetwork<? extends T>>
с P2PClient, определяющим метод setNetwork (сеть T). Я надеюсь, что этот код будет описан следующим образом:
- P2PNetwork состоит из
клиенты определенного типа.
- P2PClient может принадлежать только
сеть, клиенты которой состоят из
тот же тип, что и этот клиент (
круговая ссылка)
Это кажется правильным для меня, но если я попытаюсь создать не-общую версию, например
MyP2PClient<MyP2PNetwork<? extends MyP2PClient>> myClient;
и другие варианты. Я получаю многочисленные ошибки от компилятора. Поэтому мои вопросы таковы:
- Является ли общая круговая ссылка ровной
возможно (я никогда не видел ничего явно запрещающего его)?
- Является ли приведенное выше общее определение a
правильное определение такого кругового
отношения?
- Если это действительно так, то это "правильный"
способ описания таких отношений
(т.е. существует еще один действительный
определение, которое является стилистическим
предпочтительным)?
- Как правильно определить
не общий экземпляр Клиента и
Сервер, получивший правильный общий
определение?
Ответы
Ответ 1
Циркулярные общие ссылки действительно возможны. Java Generics and Collections содержит несколько примеров. Для вашего случая такой образец будет выглядеть следующим образом:
public interface P2PNetwork<N extends P2PNetwork<N, C>,
C extends P2PClient<N, C>> {
void addClient(C client);
}
public interface P2PClient<N extends P2PNetwork<N, C>,
C extends P2PClient<N, C>> {
void setNetwork(N network);
}
class TorrentNetwork implements P2PNetwork<TorrentNetwork, TorrentClient> {
@Override
public void addClient(TorrentClient client) {
...
}
}
class TorrentClient implements P2PClient<TorrentNetwork, TorrentClient> {
@Override
public void setNetwork(TorrentNetwork network) {
...
}
}
...
TorrentNetwork network = new TorrentNetwork();
TorrentClient client = new TorrentClient();
network.addClient(client);
Ответ 2
Это может помочь нам ответить вам, если вы определили, что означает "определенный тип", то есть различия между различными "типами" P2PNetworks.
Но вместо выражения зависимости/кругового отношения друг с другом, было бы легче выразить, введя третий класс, P2PType
:
public class P2PNetwork<T extends P2PType> {
...
}
public class P2PClient<T extends P2PType> {
...
public void setNetwork(P2PNetwork<T> network) { ... }
}
Я мог бы что-то игнорировать, но я думаю, что это позволит компилятору обеспечить, чтобы P2PClients были частью P2PNetworks того же родового типа.
Этот подход может развалиться, однако, если "тип" не является чем-то подходящим для выражения как объектно-ориентированного, т.е. если P2PType
не является тем, что имеет методы, полиморфное поведение и т.д.