经过一些测试和研究,我找到了两种替代方案来避免长时间的 switch case 情况。
- 匿名类方法(策略模式)
- 带注释的反思
使用匿名类
匿名类方法是常态,下面的代码展示了如何实现它。我在这个例子中使用了 Runnable。如果需要更多控制,请创建自定义界面。
public class ClientMessageHandler {
private final HashMap<String, Runnable> taskList = new HashMap<>();
ClientMessageHandler() {
this.populateTaskList();
}
private void populateTaskList() {
// Populate the map with client request as key
// and the task performing objects as value
taskList.put("action1", new Runnable() {
@Override
public void run() {
// define the action to perform.
}
});
//Populate map with all the tasks
}
public void onMessageReceived(JSONObject clientRequest) throws JSONException {
Runnable taskToExecute = taskList.get(clientRequest.getString("task"));
if (taskToExecute == null)
return;
taskToExecute.run();
}
}
此方法的主要缺点是对象创建。假设我们有 100 项不同的任务要执行。这种匿名类方法将导致为单个客户端创建 100 个对象。我的应用程序无法承受过多的对象创建,因为该应用程序将有超过 5,000 个活动并发连接。看看这篇文章http://blogs.microsoft.co.il/gilf/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements/ http://blogs.microsoft.co.il/gilf/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements/
带注释的反思
我真的很喜欢这种方法。我创建了一个自定义注释来表示方法执行的任务。与策略模式方法一样,没有对象创建的开销,因为任务由单个类执行。
注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TaskAnnotation {
public String value();
}
下面给出的代码将客户端请求键映射到处理任务的方法。在这里,地图仅被实例化和填充一次。
public static final HashMap<String, Method> taskList = new HashMap<>();
public static void main(String[] args) throws Exception {
// Retrieves declared methods from ClientMessageHandler class
Method[] classMethods = ClientMessageHandler.class.getDeclaredMethods();
for (Method method : classMethods) {
// We will iterate through the declared methods and look for
// the methods annotated with our TaskAnnotation
TaskAnnotation annot = method.getAnnotation(TaskAnnotation.class);
if (annot != null) {
// if a method with TaskAnnotation is found, its annotation
// value is mapped to that method.
taskList.put(annot.value(), method);
}
}
// Start server
}
最后,我们的 ClientMessageHandler 类如下所示
public class ClientMessageHandler {
public void onMessageReceived(JSONObject clientRequest) throws JSONException {
// Retrieve the Method corresponding to the task from map
Method method = taskList.get(clientRequest.getString("task"));
if (method == null)
return;
try {
// Invoke the Method for this object, if Method corresponding
// to client request is found
method.invoke(this);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
logger.error(e);
}
}
@TaskAnnotation("task1")
public void processTaskOne() {
}
@TaskAnnotation("task2")
public void processTaskTwo() {
}
// Methods for different tasks, annotated with the corresponding
// clientRequest code
}
这种方法的主要缺点是性能受到影响。与直接方法调用方法相比,此方法速度较慢。此外,许多文章建议远离反射,除非我们正在处理动态编程。
阅读这些答案以了解有关反射的更多信息什么是反射以及为什么它有用? https://stackoverflow.com/questions/37628/what-is-reflection-and-why-is-it-useful
反射性能相关文章
Java 反射的更快替代方案 https://stackoverflow.com/questions/19557829/faster-alternatives-to-javas-reflection
https://dzone.com/articles/the-performance-cost-of-reflection https://dzone.com/articles/the-performance-cost-of-reflection
最后结果
我继续在应用程序中使用 switch 语句以避免任何性能影响。