Java 用HashMap替换switch语句

Java 用HashMap替换switch语句,java,hashmap,Java,Hashmap,我有一个套接字类,它接收包(字节数组)。每个包都有一个整数以标识其类型。switch语句中的每种情况如下所示: switch(packet.getHeader().getID()) { case PingRequest.ID: if(data.length != PingRequest.SIZE) return null; PingRequest pingRequest = new PingRequest(data); /* specific parsing o

我有一个套接字类,它接收包(字节数组)。每个包都有一个整数以标识其类型。switch语句中的每种情况如下所示:

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;
...
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;
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;
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对其进行优化:

public static HashMap<Integer, Class<?>> _packetTypes = new HashMap<Integer, Class<?>>();
_packetTypes.put(PingRequest.ID, PingRequest.class);
公共静态HashMap>();
_packetTypes.put(PingRequest.ID,PingRequest.class);
我现在想要实现的是这样的目标:

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;
...
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;
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;
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);
}
Class myClass=PacketAbstract.\u packetTypes.get(packet.getHeader().getID());
类别[]cArg=新类别[1];
cArg[0]=Byte.class;
构造函数ct=myClass.getConstructor(cArg);
/*从现在开始没有任何意义*/
myClass specialPacket=ct.newInstance(数据);
specialPackage.setHeader(数据);
数据包=特殊数据包;
因此,基本的想法是创建一个hashmap,其中包含数据包id和相应的数据包类,允许我创建专门的数据包。最后一段代码是用来替换我的switch语句的

问题:

我的解决方法正确吗?如果没有,请告诉我。 我如何实现我的代码的最后一部分,这到目前为止还没有意义(如果这是正确的方法)


编辑:packet是抽象类
packet
的一个对象,它被每个特殊的包扩展,比如
PingRequest

,看起来你的想法是可行的。我认为代码应该是这样的:

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;
...
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;
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;
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
。 编辑:添加了使用枚举字段的第二个备选解决方案。

classmyclass=PacketAbstract.\u packetTypes.get(packet.getHeader().getID());
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;
类别[]cArg=新类别[1]; cArg[0]=字节[]。类;//不是Byte.class 构造函数ct=myClass.getConstructor(cArg); objectspecialpacket=ct.newInstance(数据); 方法mt=myClass.getMethod(“setHeader”,字节[].class) mt.invoke(特殊包、数据); 数据包=特殊数据包;
您是否可以使用工厂模式(例如在)

比如:

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();
       }
  }
}

Class.newInstance()
可以工作,但必须更改代码才能为这些子类使用默认构造函数。@RobI oops。。。这是个错误。修正。然后我必须为每个ID编写数百个
if(packetId==Ping_ID)
,一个if语句,这与使用switch语句相同。是的,您必须编写许多if语句,但最终避免了switch的每个case语句中重复的代码块,或者您可以修改PacketFactory getInstance(int packetId),这样它就可以从HashMap中找到子类名称(必须用key作为packetId,value作为classname来构造),然后使用stackoverflow问题中指定的答案从string中实例化类