I am writing an application to do some distributed calculations in a peer to peer network. In defining the network I have two class the P2PNetwork and P2PClient. I want these to be generic and so have the definitions of:
P2PNetwork<T extends P2PClient<? extends P2PNetwork<T>>>
P2PClient<T extends P2PNetwork<? extends T>>
with P2PClient defining a method of setNetwork(T network). What I am hoping to describe with this code is:
- A P2PNetwork is constituted of
clients of a certain type
- A P2PClient may only belong to a
network whose clients consist of the
same type as this client (the
circular-reference)
This seems correct to me but if I try to create a non-generic version such as
MyP2PClient<MyP2PNetwork<? extends MyP2PClient>> myClient;
and other variants I receive numerous errors from the compiler. So my questions are as follows:
- Is a generic circular reference even
possible (I have never seen anything explicitly forbidding it)?
- Is the above generic definition a
correct definition of such a circular
relationship?
- If it is valid, is it the "correct"
way to describe such a relationship
(i.e. is there another valid
definition, which is stylistically
preferred)?
- How would I properly define a
non-generic instance of a Client and
Server given the proper generic
definition?
Circular generic references are indeed possible. Java Generics and Collections includes several examples. For your case, such a specimen would look like this:
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);
It might help us to answer you if you further defined what "a certain type" means, i.e. what the differences are between various "types" of P2PNetworks.
But instead of expressing the dependency / circular relationship in terms of each other, it might be easier to express by introducing a third class, the P2PType
:
public class P2PNetwork<T extends P2PType> {
...
}
public class P2PClient<T extends P2PType> {
...
public void setNetwork(P2PNetwork<T> network) { ... }
}
I might be overlooking something but I think this would allow the compiler to enforce that P2PClients are a part of P2PNetworks of the same generic type.
This approach might fall apart however if the "type" isn't something that is suitable to express as a object-oriented itself, i.e. if the P2PType
isn't something that would have methods, polymorphic behavior, etc.