命令導向介面

2003 年 11 月 23 日

模組最常見的介面樣式是使用程序或物件方法。因此,如果您希望模組計算合約的一堆費用,您可以使用 BillingService 類別,並使用一個方法來執行計算,像這樣呼叫它

aBillingService.calculateCharges(aContract)

命令導向介面會為每個操作提供一個命令類別,並使用類似這樣的內容呼叫

CalculateChargeCommand.new(aContract).run()

基本上,您為方法導向介面中會有的每個方法提供一個命令類別。

常見的變化是有一個單獨的命令執行器物件,實際上執行命令的執行。

aCommandExecutor.run(CalculateChargeCommand.new(aContract))

如果您使用過 Struts 等架構,您會發現動作類別遵循這種操作樣式。

那麼,為什麼人們喜歡和不喜歡這種方法?首先,公平地說,命令導向介面比方法導向介面更為複雜。您必須實例化命令並傳遞它們以執行。這比僅呼叫方法更為複雜,這就是為什麼即使是這種方法的愛好者也只將它們用於重要的介面(服務層、伺服器端邏輯、主要子系統的介面)。

命令導向介面有很多好處。其中一個主要好處是能夠透過裝飾命令執行器,輕鬆地將常見行為新增到命令中。這對於處理交易、記錄等非常方便。命令可以排隊以供稍後執行,並且(如果命令及其資料是可序列化的)可以在網路上傳遞。命令結果可以快取,方法是針對從命令名稱和引數合成的金鑰保留結果。

在我看過關於命令的抱怨中,最大的問題是命令中有許多重複的邏輯。當命令是包含大量邏輯的交易腳本時,最容易發生這種情況。這不一定是使用命令而不是方法的問題;這個問題是交易腳本的普遍問題。命令導向結構可能會誇大這個問題,原因僅在於許多人認為一個類別需要一或兩頁的程式碼才有價值,因此最終會在命令中放入比應有的更多程式碼。

您會注意到我在本頁中使用了單字介面。這反映出使用命令的選擇主要與客戶端介面有關,而不是命令邏輯的實際實作。具有執行方法僅呼叫另一方法的單行命令類別是完全合理的。這樣做讓您擁有命令的所有優點,但允許您將邏輯保留在命令類別本身之外。此類命令類別的程式碼行數很少。

命令中常見的問題是回傳什麼。一般執行方法需要一個通用的回傳型態,例如 Object 或 CommandResult,但您會想要一個更具體的型態來取得執行命令的結果。一個途徑是為每個命令類別定義一個結果類別並使用命名慣例,因此 CalculateChargeCommand 會有 CalculateChargeResult 的回傳型態。另一個途徑是讓命令將結果儲存在同一個物件中。在這種情況下,您會先執行命令,然後詢問命令物件的結果。