我有一个接收包(字节数组)的套接字类。每个包都有一个整数,以便识别其类型。 switch语句中的每个case都是这样的:
switch(packet.getHeader().getID()) {
case PingRequest.ID:
if(data.length != PingRequest.SIZE)
return null;
PingRequest pingRequest = new PingRequest(data); /* specific parsing of the byte array */
pingRequest.setHeader(data); /* method of the abstract class */
packet = pingRequest;
break;
case Error.ID:
if(data.length != Error.SIZE)
return null;
Error error = new Error(data);
error.setHeader(data);
packet = error;
break;
...
每个数据包都有不同的信息,这就是为什么每个数据包都有不同的构造函数(从字节数组data
创建数据包成员)
由于每个案例看起来都有些相似(并且有很多案例)我认为我应该使用HashMap来优化它:
public static HashMap<Integer, Class<?>> _packetTypes = new HashMap<Integer, Class<?>>();
_packetTypes.put(PingRequest.ID, PingRequest.class);
我现在想要达到的目标是:
Class<?> myClass = PacketAbstract._packetTypes.get(packet.getHeader().getID());
Class[] cArg = new Class[1];
cArg[0] = Byte.class;
Constructor<?> ct = myClass.getConstructor(cArg);
/* Doesn't make any sense from here on */
myClass specialPacket = ct.newInstance(data);
specialPacket.setHeader(data);
packet = specialPacket;
因此,基本思想是创建一个包含数据包ID和相应数据包类的哈希映射,这将允许我创建专用数据包。最后一个代码部分用于替换我的switch语句。
问题:
我的想法是如何解决这个问题的?如果不是请赐教。 我如何实现我的代码的最后一部分到目前为止没有意义(如果这是正确的方法)?
编辑:数据包是抽象类Packet
的一个对象,它被PingRequest
答案 0 :(得分:1)
看起来你的想法会起作用。我认为代码需要是这样的:
Class<? extends Packet> myClass = PacketAbstract._packetTypes.get(packet.getHeader().getID());
Constructor<Packet> ct = myClass.getConstructor(data.getClass());
Packet specialPacket = ct.newInstance(data);
specialPacket.setHeader(data);
packet = specialPacket;
然而,在我看来,使用反射通常是最后的手段。考虑查看其他模式,例如可能有助于此类问题的Visitor Pattern。
另一种选择是在枚举中嵌入每个标识符的正确具体Class
,如下所示:
enum PacketID {
private int id;
private int size;
private Class<? extends Packet> subClass;
private PacketID(int id, int size, Class<? extends Packet> subClass) {
this.id = id;
this.size = size;
this.subClass = subClass;
}
ERROR( 1, 100, Error.class),
PINGREQ(2, 25, PingRequest.class);
}
这也可以让你抽象出我在第一个HashMap
解决方案中没有看到的尺寸检查,并且可能完全跳过HashMap
。
编辑:将参数更改为getConstructor()
,因为它似乎使用字节数组而不仅仅是Byte
。
编辑:使用枚举字段添加第二个备用解决方案。
答案 1 :(得分:0)
Class<?> myClass = PacketAbstract._packetTypes.get(packet.getHeader().getID());
Class[] cArg = new Class[1];
cArg[0] = byte[].class; // not Byte.class
Constructor<?> ct = myClass.getConstructor(cArg);
Object specialPacket = ct.newInstance(data);
Method mt = myClass.getMethod("setHeader", byte[].class)
mt.invoke(specialPacket, data);
packet = specialPacket;
答案 2 :(得分:0)
你可以使用工厂模式(例如http://alvinalexander.com/java/java-factory-pattern-example)吗?
类似于:
interface Packet {
void parse(Datatype data);
void setHeaders (Datatype data);
}
class PingPacket implements Packet {
void parse (Datatype data) {
....
....
}
void setHeaders(Datatype data) {
...
...
}
}
class ErrorPacket implements Packet {
void parse (Datatype data) {
.....
.....
}
void setHeaders(Datatype data) {
...
...
}
}
class PacketFactory {
Packet getInstance(int packetId) {
if (packetId == Ping_ID) {
...
...
return new PingPacket();
} else if (packetId == ERROR_ID) {
...
...
return new ErrorPacket();
}
}
}