我正在制作一个多人游戏,它大量使用可序列化的Event
类来通过网络发送消息。我希望能够基于常量重建Event
的适当子类。
到目前为止,我选择了以下解决方案:
public class EventFactory {
public static Event getEvent(int eventId, ByteBuffer buf) {
switch (eventId){
case Event.ID_A:
return EventA.deserialise(buf);
case Event.ID_B:
return EventB.deserialise(buf);
case Event.ID_C:
return EventC.deserialise(buf);
default:
// Unknown Event ID
return null;
}
}
}
然而,这让我感到非常啰嗦,并且每次创建新的Event
类型时都会添加一个新的“case”语句。
我知道其他两种方法可以实现这一点,但似乎都没有好转*:
有没有比我使用的方法更好的方法?我可能不理会上面提到的替代方案吗?
*注意:在这种情况下,更好的意味着更简单/更清洁,但不会影响速度太快。
答案 0 :(得分:0)
您可以使用HashMap<Integer,Event>
为eventID获取正确的事件。添加或删除事件变得很容易,随着代码的增长,与交换机案例解决方案相比,这很容易维护,而且速度方面也应该比交换机案例解决方案更快。
static
{
HashMap<Integer,Event> eventHandlerMap = new HashMap<>();
eventHandlerMap.put(eventId_A, new EventHandlerA());
eventHandlerMap.put(eventId_B, new EventHandlerB());
............
}
而不是你的switch语句现在你可以使用:
Event event = eventHandlerMap.get(eventId);
if(event!=null){
event.deserialise(buf);
}
答案 1 :(得分:0)
如果你不害怕反思,你可以使用:
private static final Map<Integer, Method> EVENTID_METHOD_MAP = new LinkedHashMap<>();
static {
try {
for (Field field : Event.class.getFields())
if (field.getName().startsWith("ID_")) {
String classSuffix = field.getName().substring(3);
Class<?> cls = Class.forName("Event" + classSuffix);
Method method = cls.getMethod("deserialize", ByteBuffer.class);
EVENTID_METHOD_MAP.put(field.getInt(null), method);
}
} catch (IllegalAccessException|ClassNotFoundException|NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Event getEvent(int eventId, ByteBuffer buf)
throws InvocationTargetException, IllegalAccessException {
return (Event) EVENTID_METHOD_MAP.get(eventId).invoke(null, buf);
}
此解决方案要求int ID_N
始终映射到class EventN
,其中N
可以是任何字符串,其中所有字符都返回true
方法java.lang.Character.isJavaIdentifierPart(c)
。此外,class EventN
必须定义一个名为deserialize
的静态方法,其中一个ByteBuffer
参数返回Event
。
在尝试获取其字段值之前,您还可以检查field
是否为静态。我现在忘记了如何做到这一点。