經過一番測試和研究後,我發現了兩種方法來避免長時間切換的情況。
- 匿名類方法(策略模式)
- 思考與註解
使用匿名類
匿名類方法是常態和下面的代碼顯示如何實現它。在這個例子中我使用了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/
反思與註釋
我真的很喜歡這種方法。我創建了一個自定義註釋來表示由方法執行的任務。對象創建沒有任何開銷,就像在Strategy模式方法中一樣,因爲任務是由一個類執行的。
註釋
@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
}
主要缺點是對性能的影響。與直接方法調用方法相比,此方法速度較慢。此外,許多文章都建議遠離Reflection,除非我們正在處理動態編程。
閱讀這些答案更多地瞭解反射What is reflection and why is it useful?
反射性能相關的文章
Faster alternatives to Java's reflection
https://dzone.com/articles/the-performance-cost-of-reflection
最終結果
我繼續在我的應用程序中使用switch語句以避免任何性能問題。
關於'@endpoint ...',你在談論javax.xml.ws.Endpoint嗎?這看起來很web服務,而不是websocket。 AFAIK,websocket是Java EE環境(JSR 356)中的唯一標準。其他方面,指的是可以通過[Reflection](https://stackoverflow.com/a/161005/4906586)完成方法,但恕我直言,長開關更容易處理 – Al1
它的websocket只。如果我沒有錯,像Spring這樣的框架使用@endpoint註釋來將API請求定向到特定的方法/類。我想,如果我能得到這個註解的底層實現,我可以建立類似的東西。例如,當客戶端發送請求登錄時,我可以將請求轉發到特定的方法來執行任務,而不使用任何條件語句。 –
這是我正在談論的註釋。 @ServerEndpoint是如何工作的?http://docs.oracle.com/javaee/7/api/javax/websocket/server/ServerEndpoint.html –