一、簡介
Command pattern是一套基於Spring Framework ,以Use Case為中心的架構。它糅合了幾種經典的JavaEE設計模式,使應用開發人員在實現Use Case時,能夠更專註於商業邏輯本身。
結構圖:
整個業務層都是用Spring架構來配置的。Spring是一種輕量的IoC的架構,使用Spring能夠最大程度上保證商務邏輯不被汙染
表現層調用商務邏輯層的流程圖:
二、具體流程
1. 用戶端
如何調用一個商務邏輯呢?對於商務邏輯的調用者(通常是表現層),完全不用關心這個商務邏輯是如何?的。對用戶端而言,它只能看到command dispatcher,如:
對需要調用業務操作的Web層組件,其內聚了一個CommandDispatcher,通過該dispatcher來完成業務的委派,但是這個commandDispatcher就是一個Bean,它存在於Spring容器之中(可以參考web層的模組ioc)。缺點在於web層被command所侵入,並且與業務實現在一定程度上發生了耦合。
步驟:
a)建立一個Command,填上商務邏輯所需要的參數。
b)將Command對象傳遞給CommandDispatcher,這樣就完成了商務邏輯的調用。
c)如果需要,可以取得商務邏輯的返回結果。
// Step 1. 裝配一個command,// command名稱為"userCommand","userCommand"中有許多有關user的子命令,// 而"registerUser"是其中的一個子命令。(子命令參數是可選的)Command command = new CommandSupport("userCommand", "registerUser");commandName.getParameters().put("name", "michael");commandName.getParameters().put("password", "helloworld");commandName.getParameters().put("email", "michael@hello.world");// Step 2. 調用商務邏輯Result result = getDispatcher().execute(command);// Step 3. 處理返回結果if (result.isSuccess()) { User user = (User) result.getModels().get("user"); // 通常這類操作會返回資料庫所建立的sequence ID。 int id = user.getId(); ...} else { ResultCode errorCode = result.getResultCode(); if (errorCode == UserResultCode.USER_ALREADY_EXISTS) { ... } ...}
2. 服務端
服務端,它也不需要瞭解用戶端的情況。服務端要做的,無非是從系統接收command的請求,然後執行相應的商務邏輯而已。
步驟:
a)建立ApplicationObject(即AO)。
實現ApplicationObject介面,但建議從ApplicationObjectSupport繼承
public class LoginAO extends ApplicationObjectSupport {}
b)執行
類似於WebX中的action,AO可以根據command中的event參數來自動調用相應的方法,例如 new CommandSupport("loginAO", "login"),那麼,只要實現下面的方法即可
public Result doLogin() { Account user = userManager.login(userId, password); Result result = new ResultSupport(); if (user == null) { result.setSuccess(false); result.setResultCode( LoginResultCode.INVALID_USER_OR_PASSWORD); } else { result.setDefaultModel("user", user); } return result;}如果沒有提供event參數,或未匹配event,那麼預設的doPerform()方法將被執行
3. CommandDispatcher 實現
CommandDispatcher是一個“分發器”。它的功能就是根據command的名字找到相應的商務邏輯對象,並執行之。每一個商務邏輯對象對應一個或一組相關的use case。例如:在使用者管理系統中,使用者的建立、刪除、修改等操作可以看作一個use case,因而我們可以寫一個商務邏輯對象——“UserManagementAO”——來處理這個use case。“AO”是“ApplicationObject”的縮寫,每一個AO必須實現ApplicationObject介面。
CommandDispatcher有多種實現,以適應多種需要:
序號 |
CommandDispatcher的實現 |
說明 |
1. |
Stateless Session Bean (CommandDispatcherBean) |
使用Stateless Session Bean來分發Command。該實現允許進行分布式的商業邏輯調用。 |
2. |
Message-driven Bean (CommandDispatcherClient) |
通過Message-driven Bean來分發Command,通過JMS來發送Command請求。該實現允許進行非同步商業邏輯調用。 |
3. |
Plain Javabean (CommandDispatcherLogic) |
通過普通的Javabean來分發Command。這個實現非常適合在非EJB的環境下調用商業邏輯。 |
4. |
NOOP (CommandDispatcherNoop) |
不做任何事情的分發器。這個實現非常適合在程式的開發階段,用來偵錯工具。或者當商業邏輯還未開發完成時,調用者可以利用該分發器來“調用”商業邏輯,以便調用者的代碼可以被順利地開發。 |
5. |
Selector (CommandDispatcherSelector) |
該分發器可根據Command的內容來自動先擇合適的其它CommandDispatcher。這樣,我們就可以更方便地控制CommandDispatcher的行為。例如,在調用者完全不知情的情況下,將某個Command的處理轉變為利用Message-driven bean來非同步處理。 |
儘管有這麼多種CommandDispatcher的實現,但是表現層完全不用瞭解這些細節。所有的CommandDispatcher都是通過spring來配置的
4. 小結
Command Pattern是基於request-response的模式。用戶端建立command,服務端響應command並返回結果給用戶端 —— 類似WEB層的模式。而用戶端和服務端是通過command dispatcher來串連的。
這種模式有什麼好處呢?
最大的好處,就是用戶端和服務端完全分離。無論是Web-tier還是Biz-tier都不用瞭解command分發的細節 —— 這些細節對代碼是透明的。
其次,所有的CommandDispatcher都是通過spring來配置的,因此也很容易建立新的CommandDispatcher模式。目前已經支援同步、非同步等操作。
那麼,這種模式有什麼缺點呢?任何設計模式都有適用的場合,也有不利的一面。Command Pattern也不例外。
這種模式最大的缺點是,沒有一種統一的方法,可以知道商務邏輯層所需要的參數個數、類型,同樣也很難知道傳回值的數量和類型。這樣會增加用戶端/服務端程式員交流的成本。