特別注意Client中的
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
個人理解,這兩塊大的區(qū)別是Invoker調(diào)用的是一個借口類(當然在實際中可以也可以不是),在識別Invoker時注意調(diào)用的對象是否是一個接口對象。兩外,命令模式各個角色之間的關(guān)系如下圖所示。
Client和Invoker之間是一種弱關(guān)聯(lián)的依賴關(guān)系。
在Junit為什么要適用命令模式呢?Junit中使用命令模式有什么好處呢?
先看看在Junit中為什么要使用命令模式,在這我們先看看Junit的執(zhí)行過程的時序圖,啟動一次執(zhí)行時,TestRunner先解析加載后,然后通過TestSuite、TestCase中的run方法繼續(xù)解析成一個個Junit的測試方法(testcase),緊接著通過TestResult調(diào)用TestCase中的執(zhí)行方法,通過TestCase中的runBare方法終調(diào)我們自己寫的測試代碼(含有testXXX的測試方法)。
通過對Junit代碼的分析,TestRunner相當于命令模式中的客戶(Client)角色,在TestRunner中main方法和doRun方法中的實現(xiàn)和命令模式中的Client的代碼實現(xiàn)非常相似,具體如下
public static void main(String args[]) {
TestRunner aTestRunner= new TestRunner();
try {
TestResult r= aTestRunner.start(args);
//在start方法通過調(diào)用返回doRun方法
} catch(Exception e) {
System.err.println(e.getMessage());
System.exit(EXCEPTION_EXIT);
}
}
public TestResult doRun(Test suite, boolean wait) {
TestResult result= createTestResult();
result.addListener(fPrinter);
long startTime= System.currentTimeMillis();
suite.run(result);
long endTime= System.currentTimeMillis();
long runTime= endTime-startTime;
fPrinter.print(result, runTime);
pause(wait);
return result;
}
而命令(Command)角色是Junit中的TestCase(繼承Test)。
具體命令(ConcreteCommand)是我們所寫的測試方法,比如testXXX等所在的類
具體請求者(Invoker)則是TestResult,通過TestResult調(diào)用run方法,進而調(diào)用執(zhí)行方法,
在Junit真正執(zhí)行調(diào)用測試用例testcase則是在Junit中TestCase真正實現(xiàn)后的執(zhí)行,所有說接收者(Receiver)接收者是TestCase,TestCase在命令模式中充當了多個角色,當然這塊也可以在加一個類TestRun實現(xiàn)測試測試執(zhí)行。但不知作者為什么要直接在TestCase中實現(xiàn)測試代碼的終執(zhí)行?
后我們再說說在這塊用命令模式有什么好處?
我理解在這塊大的好處是,解耦了具體命令者(我們自己寫的testXXX方法)和TestCase,兩外,實現(xiàn)了測試執(zhí)行者TestRUnner和命令接受者TestResult的耦合,是命令請求和命令執(zhí)行的對象分割。
另外補充一點,對于大多數(shù)請求-響應(yīng)模式的功能,比較適合使用命令模式,正如命令模式定義說的那樣,命令模式對實現(xiàn)記錄日志、撤銷操作等功能比較方便。