設計模式(七):命令模式

来源:http://www.cnblogs.com/lovesong/archive/2016/06/21/5605076.html
-Advertisement-
Play Games

這個模式我在書上(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
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 程式運行為什麼需要記憶體(一) 1、程式的目的是運行得到一定的結果。 2、為了得到不同的結果,就要運行不同的程式。 3、電腦程式的本質都是在做計算,計算就是在計算數據,所以電腦程式中重要的部分就是數據。 電腦程式 = 代碼 + 數據 4、從巨集觀上理解代碼就是動作,即加工數據的動作。數據就是數字, ...
  • 考試科目: 添加考試科目,填寫科目名稱,選擇科目題型(覆選框/單選題,多選題,判斷題,問答題,填空題) 添加科目章節,填寫章節名稱,添加章節知識點,填寫知識點以英文逗號分隔,直接插入多條記錄 開通考場: 填寫考場名稱,選擇考場狀態(開啟/關閉),選擇考試科目(下拉框) 考試試題: 添加試題,選擇題型 ...
  • 本章內容: Socket IO多路復用(select) SocketServer 模塊(ThreadingTCPServer源碼剖析) socket通常也稱作"套接字",用於描述IP地址和埠,是一個通信鏈的句柄,應用程式通常通過"套接字"向網路發出請求或者應答網路請求。 功能: sk = sock ...
  • 恢復內容開始 最近嘗試在MAC(OS X 10.11 El Capitan)上安裝Caffe 以及Python介面遇到了一些問題但是官方安裝教程上並沒有提出這些問題的解決辦法搜索了很久(主要在於Python介面上) 終於找到瞭解決辦法 其實Caffe的安裝分兩步:安裝依賴+編譯源碼 首先是安裝依賴: ...
  • 今天在剛申請了博客,一下午都在寫那個隨筆,所以說好的來看c++的也放在了最後,下星期就考試了,這個類的靜態成員是我不是很懂的,在網上 看到一片很詳細的博客考下來回去慢慢看。 在C++中,靜態成員是屬於整個類的而不是某個對象,靜態成員變數只存儲一份供所有對象共用。所以在所有對象中都可以共用它。使用靜態 ...
  • 最近由於項目需要,研究了一下maven的打包,項目要做到 1,生成3個目錄/lib,/conf,/bin目錄 2,把所有的jar目錄編譯、拷貝到/lib目錄(包括maven的jar包和lib目錄下的jar,以及編譯的jar包) 3,把所有的啟動腳本從工程根目錄拷貝到/bin目錄 4,把所有的配置文件... ...
  • 課本源碼部分 第9章 查找 - 雙鏈樹(鍵樹) ——《數據結構》-嚴蔚敏.吳偉民版 源碼使用說明 鏈接☛☛☛ 《數據結構-C語言版》(嚴蔚敏,吳偉民版)課本源碼+習題集解析使用說明 課本源碼合輯 鏈接☛☛☛ 《數據結構》課本源碼合輯 習題集全解析 鏈接☛☛☛ 《數據結構題集》習題解析合輯 本源碼引入 ...
  • 很長時間了,有兩個想要完成的事情,在這裡寫下來,督促自己完成它們。 第一個事情是實現一個模板系統,主要特點: 實現文檔和代碼之間的強聯繫,最外層的模板代碼即文檔 分離關註。不同邏輯部分可以放在不同的文件或代碼段里,即便最終生成的代碼不可避免地混合 跨語言。比如在server端和javascript部 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...