2008-12-28 86 views
10

對於我的Java遊戲服務器,我發送數據包的操作ID,它基本上告訴服務器數據包的用途。我想將每個Action ID(一個整數)映射到一個函數。有沒有辦法做到這一點,而不使用開關?Java中的函數指針/代表?

+0

總體而言,交換機將會更好。 – TheSoftwareJedi 2008-12-28 12:44:38

+0

是的,開關幾乎肯定會更快,更小,更乾淨。 – 2008-12-28 13:30:32

+1

[Java中函數指針最接近的替代函數是什麼?](http://stackoverflow.com/questions/122407/whats-the-nearest-substitute-for-a-function-pointer-in-java) – Raedwald 2013-02-25 13:36:27

回答

21

這個怎麼樣? (如果您需要傳遞一些參數,請使用具有合適參數的函數定義您自己的接口,然後使用該參數代替Runnable)。

+3

我認爲functionA和functonB被調用的開關會更清晰的代碼。這只是將ID映射到函數到您要加載映射的代碼段,而不是調用函數的位置。 – 2008-12-28 04:47:24

1

Java沒有一流的函數指針。爲了實現類似的功能,你必須定義和實現一個接口。你可以使用匿名內部類更容易,但它仍然不是很漂亮。這裏有一個例子:

public interface PacketProcessor 
{ 
    public void processPacket(Packet packet); 
} 

... 

PacketProcessor doThing1 = new PacketProcessor() 
{ 
    public void processPacket(Packet packet) 
    { 
     // do thing 1 
    } 
}; 
// etc. 

// Now doThing1, doThing2 can be used like function pointers for a function taking a 
// Packet and returning void 
+0

有關Java中的「函數指針」的更多信息,請參閱:http://stackoverflow.com/q/122407/545127 – Raedwald 2013-02-25 13:35:31

1

你有沒有使用Swing/AWT?他們的事件層次結構解決了類似的問題。圍繞Java的功能傳遞方式是一個接口,例如

public interface ActionHandler { 
    public void actionPerformed(ActionArgs e); 
} 

然後,如果你想整數映射到這些對象,你可以使用像一個java.util.HashMap<Integer,ActionHandler>來管理。實際的實現可以使用匿名類(Java的「lambda」的最佳近似值),也可以放在適當的類中。這裏的匿名類方式:

HashMap<Integer,ActionHandler> handlers; 
handlers.put(ACTION_FROB, new ActionHandler() { 
    public void actionPerformed(ActionArgs e) { 
     // Do stuff 
     // Note that any outer variables you intend to close over must be final. 
    } 
}); 
handlers.get(ACTION_FROB).actionPerformed(foo); 

(編輯)如果你想更加辱罵,你可以初始化HashMap中,像這樣:

HashMap<Integer,String> m = new HashMap<Integer,String>() {{ 
    put(0,"hello"); 
    put(1,"world"); 
}}; 
2

的Java並沒有真正有函數指針(我們取而代之的是匿名內部類)。但是,使用開關真的沒什麼問題,只要你打開價值而不是打開類型。有沒有理由不想使用交換機?看起來你需要在代碼中的某處執行Action ID和動作之間的映射,爲什麼不簡單呢?

0

您可以通過使用責任鏈模式來做到這一點。

這是一種將不同對象鏈接在一起的模式,如鏈接列表。即每個對象都有一個對鏈中下一個的引用。鏈中的對象通常處理一個特定的行爲。對象之間的流程與switch-case語句非常相似。

有一些問題,例如,它將您的邏輯分散開來,過長的鏈會導致性能問題。但是隨着這些問題的發生,您可以獲得更高的可測試性和更強的凝聚力。此外,您不限於將enum,byte,int short和char表達式用作分支的觸發器。

1

呀,但使用的接口意味着你必須創建,這意味着要通過它設置的每個函數每次回調的接口。創建一個委託類來處理這個問題給你(不是一個真正的函數指針),而是要傳遞的函數,如果你濫用通用類型作爲返回類型,那麼你不必將瓶頸下降到幾乎沒有。

c#委託(MultiCastDelegate是正確的)從使用方法MethodInfo獲取信息,這與使用java.lang.reflect.method的Delegate類需要做的事情是一樣的。我在本網站的另一種形式上發佈了代理(T)類的代碼,處理這個問題。我做它是因爲(是)來自C++我需要一個更好的方式來傳遞函數(尤其是Void),然後必須創建一個函數或更多的接口。現在我可以選擇填充參數信息的函數。 Voila`! JIT或JVM的速度沒有明顯的下降,很好用。如果我只有一個星期只學習java編程,任何java程序員都可以做到。

另外,它在創建基本偵聽器和基本接口以傳入偵聽器時效果很好。由於函數的名稱已更改,因此不必再編寫另一個偵聽器。創建委託類具有很大的優勢,因爲非常有用並且可以通過。

0

您可以接口靜態方法。該方法允許您指定參數。聲明你的界面...

public interface RouteHandler { 
    void handleRequest(HttpExchange t) throws IOException; 
} 

而且你的地圖...

private Map<String, RouteHandler> routes = new HashMap<>(); 

然後實現匹配接口/ PARAMS靜態方法......

public static void notFound(HttpExchange t) throws IOException { 
    String response = "Not Found"; 

    t.sendResponseHeaders(404, response.length()); 
    OutputStream os = t.getResponseBody(); 
    os.write(response.getBytes()); 
    os.close(); 
} 

可以再加入這些方法進入你的地圖...

routes.put("/foo", CoreRoutes::notFound); 

,並按如下方式調用它們:

RouteHandler handler = routes.get("/foo"); 
handler.handleRequest(exchange);