基于Java中的一些常量动态实例化类



我正在制作一款多人游戏,它大量使用可序列化的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'语句。

我知道有两种方法可以做到这一点,但似乎没有一种更好*:

  1. 创建常量->事件子类的映射,并使用clazz.newInstance()实例化它们(使用空构造函数),然后使用clazz.initialiase(buf)提供必要的参数。
  2. 创建一个常量->事件子类的映射,并使用反射在适当的类中找到并调用正确的方法。

是否有比我现在使用的更好的方法?也许我忽视上面提到的其他选择是不明智的?


*注意:在这种情况下,更好的意思是更简单/更干净,但不会牺牲太多的速度。

您可以使用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);
   }

如果你不怕反射,你可以使用:

    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可以是任何字符串,其中所有字符返回java.lang.Character.isJavaIdentifierPart(c)方法的true。此外,class EventN必须定义一个名为deserialize的静态方法,该方法带有一个返回EventByteBuffer参数。

你也可以检查field是否是静态的,然后再尝试获取它的字段值。我现在忘记怎么做了

相关内容

  • 没有找到相关文章

最新更新