在服务器代码中,我有一个ProtocolHandler
从套接字读取的类,找出它正在处理的数据包类型并将其分发给客户端.我正在尝试使用以下架构:
public interface Packet { //... } public class ClientInformations implements Packet { //... } public class ProtocolHandler { //.... public void bytesReceived(byte[] bytes) { //... Determine the type of the packet Packet packet = determineTypeOfPacketAndRead(bytes); // Here I already have the packet object built, // like ClientInformations@1a1a1a1a[...] client.packetReceived(packet); } //... } public class Client { //... public void packetReceived(Packet pkt) { System.out.println("Unimplemented packet received."); } public void packetReceived(ClientInformations ci) { } //... }
(我不知道如何用文字轻松解释).问题是,我真的以为packetReceived(ClientInformations)
会被召唤,但事实并非如此.它称之为更通用的packetReceived(Packet)
方法.我错了吗?那我怎么还能使用相同的架构呢?
- 编辑
现在我明白为什么会这样.问题是,我有其他分组类,例如Movement
,Sync
,Spawn
.我想通过向类中添加新方法来轻松添加新数据包Client
.那不是另一种方式吗?我的意思是,一种 在运行时自动分析packet
对象类型并执行最具体方法调用的方法?
我假设你有Packet packet = determineTYpeOfPacketAndRead(bytes)
,因为代码几乎没有其他方式可以编译.
所以引用类型是Packet
(在编译时),即使对象类型是ClientInformations
(在运行时).
并且在Java语言规范第15章中指定了方法重载.
在编译时选择最具体的方法; 它的描述符确定在运行时实际执行的方法.
更新:您的代码目前正常工作,因为您的代码中没有歧义,即使它没有按您希望的方式运行.但是,您将无法扩展此代码,因为它会导致问题,让我说明一下:
我之前提出的建议如下:
public class Client { //... public void unknownPacketReceived(Packet pkt) { System.out.println("Unimplemented packet received."); } public void packetReceived(ClientInformations ci) { } //... }
然而,这不能工作,因为ClientInformations
对象是一个更复杂的东西作为一个简单的Packet
对象/接口,它将给出以下编译错误:
incompatible types: Packet cannot be converted to ClientInformations
这种情况发生在引用类型仍然只有Packet
,而你想把它提升为a ClientInformations
.
但是,如果您将其称为:
client.receivedPacket((ClientInformations)packet)
这在你的情况下没有坏处,因为在运行时它们是相同的类型,所以在转换中没有任何东西丢失,这需要伴随一instanceof
棵树,这就是你现在回到零步的原因.
这个程序不只是起作用,如果你希望它变得简单,我建议改变你的设计,如果你正在研究一个遗留应用程序并且不能只改变一些东西,那么继续这条路可能是一个选择,但它赢得了'很容易.