這個模式我在書上(JavaScript設計模式)的那個章節來來回回看了幾遍,有兩個關鍵點並沒有說清楚,導致儘管錶面上是很簡單明瞭,但本質沒有說清,以下是書上的例子。 書中淡解 例子(改前): 例子(改後,命名模式): 我想不明白,憑什麼加上這個方法,就得到了優化,哪裡就解耦了。 當carManage ...
這個模式我在書上(JavaScript設計模式)的那個章節來來回回看了幾遍,有兩個關鍵點並沒有說清楚,導致儘管錶面上是很簡單明瞭,但本質沒有說清,以下是書上的例子。
書中淡解
例子(改前):
var carManager = { // request information requestInfo: function( model, id ){ return "The information for " + model + " with ID " + id + " is foobar"; }, // purchase the car buyVehicle: function( model, id ){ return "You have successfully purchased Item " + id + ", a " + model; }, // arrange a viewing arrangeViewing: function( model, id ){ return "You have successfully booked a viewing of " + model + " ( " + id + " ) "; } }; carManager.arrangeViewing("Ferrari", "14523" ); carManager.requestInfo("Ford Mondeo", "54323" ); carManager.requestInfo("Ford Escort", "34232" ); carManager.buyVehicle("Ford Escort", "34232" );
例子(改後,命名模式):
carManager.execute = function ( name ) { return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) ); }; carManager.execute( "arrangeViewing", "Ferrari", "14523" ); carManager.execute( "requestInfo", "Ford Mondeo", "54323" ); carManager.execute( "requestInfo", "Ford Escort", "34232" ); carManager.execute( "buyVehicle", "Ford Escort", "34232" );
我想不明白,憑什麼加上這個方法,就得到了優化,哪裡就解耦了。
當carManager的API改變時候,調用這些API的對象當然都需要做修改,無論是改前、或者改後的代碼寫法。
PS:所以感覺例子不當。
網上見解
我帶著疑問,放下書本,在網上尋找資料。我發現JavaScript實現的命令模式,都是類似上面的,而其他面向對象語言的實現,就是正正經經的按照模式的類圖(如下)。於是,我就奇怪了,為什麼JavaScript和麵向對象的例子區別這麼大,按理說模式應該與實現語言無關,特別是理論部分,更沒有說到一塊去(大部分)。
-
客戶(Client)角色:創建了一個具體命令(ConcreteCommand)對象並確定其接收者。
-
命令(Command)角色:聲明瞭一個給所有具體命令類的抽象介面。這是一個抽象角色。
-
具體命令(ConcreteCommand)角色:定義一個接受者和行為之間的弱耦合;實現Execute()方法,負責調用接收考的相應操作。Execute()方法通常叫做執方法。
-
請求者(Invoker)角色:負責調用命令對象執行請求,相關的方法叫做行動方法。
-
接收者(Receiver)角色:負責具體實施和執行一個請求。任何一個類都可以成為接收者,實施和執行請求的方法叫做行動方法。
例子:
public interface Command { public void execute(); } public class ConcreteCommand implements Command { private Receiver receiver = null; private String state; public ConcreteCommand(Receiver receiver){ this.receiver = receiver; } public void execute() { receiver.action(); } } public class Receiver { public void action(){ //真正執行命令操作的功能代碼 } } public class Invoker { private Command command = null; public void setCommand(Command command) { this.command = command; } public void runCommand() { command.execute(); } } public class Client { public void assemble(){ //創建接收者 Receiver receiver = new Receiver(); //創建命令對象,設定它的接收者 Command command = new ConcreteCommand(receiver); //創建Invoker,把命令對象設置進去 Invoker invoker = new Invoker(); invoker.setCommand(command); } }
我的見解
首先命令(Command)模式是行為設計模式。
定義:
命令模式是將方法調用、請求或操作(Receiver類里的方法)封裝到一個中間者(command類),供調用者(Invoker)調用。調用者不需要知道接收者的任何介面。
例子:
Command模式的代碼都是針對圖形界面的,它實際就是菜單命令,我們在一個下拉菜單選擇一個命令時,然後會執行一些動作。
將這些命令封裝成在一個類中,然後用戶(調用者)再對這個類進行操作,這就是Command模式。換句話說,本來用戶(調用者)是直接調用這些命令的,如菜單上打開文檔(調用者),就直接指向打開文檔的代碼,使用Command模式,就是在這兩者之間增加一個中間者,將這種直接關係拗斷,同時兩者之間都隔離,基本沒有關係了。
簡而言之,本來是調用者直接調接收者代碼的,不過Command模式在兩者間加了一層中間者,中間者封裝接收者動作,調用者直接調中間者。
使用場景:
1. 圖形界面的菜單命令。
2. 需要支持命令的撤消(undo)。
優點:
1. 解耦了發送者和接受者之間聯繫。發送者調用一個操作,接受者接受請求執行相應的動作,因為使用Command模式解耦,發送者無需知道接受者任何介面。
2. 它能實現Undo功能。每個具體命令都可以記住它剛剛執行的動作,並且在需要時恢復。
缺點:
濫用設計模式的帶來的弊端而已。
總結
在仔細查閱資料後,關於上面面向對象語言和JavaScript的各自實現例子,我認為面向對象語言是更為準確,而JavaScript是不恰當的。JavaScript的例子根本沒有做到接收者與調用者的解耦,雖然carManager.execute看起來像中間者,但調用者需要知道接收者裡面的介面,這裡是耦合了。所以,JavaScript實例看看就算了,並不正確。
另外有篇文中講的,設計模式一個"通病":好象喜歡將簡單的問題複雜化,喜歡在不同類中增加第三者,當然這樣做有利於代碼的健壯性、可維護性、還有復用性。這一點也有同感。
參考文獻
1. http://www.jdon.com/designpatterns/command.htm (設計模式之Command)
2. http://www.cnblogs.com/zhenyulu/articles/69858.html (命令(Command)模式)
本文為原創文章,轉載請保留原出處,方便溯源,如有錯誤地方,謝謝指正。 本文地址 :http://www.cnblogs.com/lovesong/p/5605076.html