一、簡介
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", "[email protected]");
// 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也不例外。
這種模式最大的缺點是,沒有一種統一的方法,可以知道業務邏輯層所需要的參數個數、類型,同樣也很難知道返回值的數量和類型。這樣會增加客戶端/服務端程序員交流的成本。