Java 如何避免使用instanceof/如何在此处使用多态性
我正在开发我的第一个网络应用程序,我发现了一些我不知道如何解决的问题。我对paquets有以下层次结构Java 如何避免使用instanceof/如何在此处使用多态性,java,inheritance,handler,instanceof,Java,Inheritance,Handler,Instanceof,我正在开发我的第一个网络应用程序,我发现了一些我不知道如何解决的问题。我对paquets有以下层次结构 interface Packet {} class NewClientPacket implements Packet {} class DisconnectPacket implements Packet {} class DataPacket implements Packet {} ... 现在,服务器需要处理客户机发送的任何数据包,并对每个数据包执行不同的操作。我要写的第一件事是:
interface Packet {}
class NewClientPacket implements Packet {}
class DisconnectPacket implements Packet {}
class DataPacket implements Packet {}
...
现在,服务器需要处理客户机发送的任何数据包,并对每个数据包执行不同的操作。我要写的第一件事是:
Packet packet = (Packet) myStream.readObject();
if (packet instanceof NewClientPacket) {
...
} else if (packet instanceof DisconnectPacket {
...
} else if (packet instanceof DataPacket) {
...
}
...
但是我一点也不喜欢这个(它使用instanceof
,当添加很多新的数据包
子类时,伸缩性很差,而且非常冗长……)
我发现通常当我必须使用instanceof时,我可以通过使用多态性来避免它,因此我考虑将数据包
接口更改为
interface Packet {
void handle(PacketHandler handler);
}
然后我就可以做了
Packet packet = (Packet) myStream.readObject();
packet.handle(this);
但我不知道这是否是解决问题的好办法。你能推荐其他人吗,或者对我的评论吗?这是一个
首先,您需要一位访客
public class PacketVisitor {
void visit(NewClientPacket packet);
void visit(DisconnectPacket packet);
void visit(DataPacket packet);
}
然后,您需要将一个方法添加到接口数据包中
:
interface Packet {
void accept(PacketVisitor visitor);
}
现在,在每个数据包中
需要实现以下方法:
public class NewClientPacket implements Packet {
@Override
public void accept(PacketVisitor visitor) {
visitor.visit(this);
}
}
最后,在您的服务代码中:
final PacketVisitor visitor = new PacketVisitor() {
//implementation...
}
final Packet packet = (Packet) myStream.readObject();
packet.accept(visitor);
将发生的情况是,
PacketVisitor
的相关visit
方法将被调用为PacketVisitor
上的Packet
调用visit
的实例 I在这个上下文中,唯一知道并且应该知道其实际类型的对象是数据包
实例。因此,您将编写一个处理程序
,该处理程序被提供给数据包
,并从那里进行调度。这将类似于以下内容:
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);
}
}
所有实现都将根据其类型调用正确的
handle
方法。这种方法被称为。实际上,应该为方法选择不太通用的名称,以使代码更具可读性。通常,会使用特定于域的名称。虽然访问者模式可以为您解决这个问题,但您需要注意您的依赖关系。您可能希望将所有内容拆分为3个单独的包:
- 客户专用
- 仅服务器
- 共享类
abstract class Dispatcher {
public abstract void handleX(X x);
public abstract void handleX(Y y);
}
class X extends Packet {
public void dispatch(Dispatcher d) {
d.handleX(this);
}
}
就我个人而言,我不是这个模式的最大粉丝,因为它迫使你在每次添加新数据包时向访问者添加方法,但这就是你对它进行检查和编译时类型检查的方式。对于少量到中等数量的数据包,这可能是您会找到的最好的解决方案
实际上,牺牲编译时安全性并使用命名约定和反射找出合适的数据包处理程序可能更方便。这基本上就是访问者模式,这是使用多态性解决问题的常用方法。