I this context, the only object that is and should be aware of its actual type is the Packet
instance. You would therefore write a Handler
that is given to the Packet
and dispatched from there. This would look something like the following:
interface Handler {
void handle(NewClientPacket packet);
void handle(DisconnectPacket packet);
void handle(DataPacket packet);
}
interface Packet {
void dispatch(Handler handler)
}
class NewClientPacket implements Packet {
@Override
public void dispatch(Handler handler) {
handler.handle(this);
}
}
class DisconnectPacket implements Packet {
@Override
public void dispatch(Handler handler) {
handler.handle(this);
}
}
class DataPacket implements Packet {
@Override
public void dispatch(Handler handler) {
handler.handle(this);
}
}
All implementations will invoke the correct handle
method by their type. This approach is named the Visitor Pattern. In reality, you should choose less generic names for the methods to make your code better readable. Often, domain-specific names are used.