112

這兩種設計模式都封裝了算法,並將實現細節與其調用類分離。唯一的區別是我可以看出,戰略模式需要執行的參數,而命令模式則沒有。使用策略模式和命令模式

在我看來,命令模式要求創建時所有的執行信息都可用,並且它能夠延遲其調用(可能作爲腳本的一部分)。

什麼決定指導是否使用一種模式或其他?

回答

88

我正在包含幾個GoF設計模式的封裝層次表,以幫助解釋這兩種模式之間的差異。希望它能更好地說明每個封裝的內容,所以我的解釋更有意義。

首先,層次結構列出了給定模式適用的範圍,或者根據您開始的表的哪一側來封裝某個級別的細節的適當模式。

design pattern encapsulation hierarchy table

你可以從表中看到,一個戰略格局中的物體隱藏算法的實現細節,所以採用了不同的策略對象將執行相同的功能,但以不同的方式。每個策略對象可能會針對特定因素進行優化或者針對其他參數進行操作;並且通過使用通用接口,上下文可以安全地與任一接口一起工作。

命令模式封裝比算法小得多的細節級別。它編碼發送消息到對象所需的細節:接收器,選擇器和參數。客觀化流程執行的這一小部分的好處是可以在不同時間點或位置以一般方式調用這些消息,而不必對其細節進行硬編碼。它允許消息被調用一次或多次,或者傳遞到系統或多個系統的不同部分,而不需要在執行之前知道具體調用的細節。

正如設計模式的典型代表,它們並不要求所有的實現都具有相同的細節以承載模式名稱。細節可以在實現中以及在對象中編碼的數據與作爲方法參數的編碼中有所不同。

+0

因此,如果我有一個系統用「過濾器管道」過濾結果並使用委託作爲過濾器(其中每個過濾器的算法都封裝在一個函數內)是否會被視爲命令模式?在這種情況下,我將過濾函數的委託視爲爲每個過濾器在輸入和輸出方面必須遵循的內容提供排序合約。 – KTF 2012-09-28 12:38:21

+3

@KTF,no。 Command模式使用一個對象,它擁有大多數(如果不是全部的話)所需的信息(例如接收器,選擇器,參數)來調用對象的方法。這是一種簡單化的模式,可用於其他設計模式,例如您所描述的責任鏈,集合和管道模式。您的代表提供的「各種合同」是另一種模式,即界面。 – Huperniketes 2012-10-02 09:58:49

15

我看待它的方式是,您有多種方式來做同樣的事情,每一種方法都是一種策略,並且運行時決定執行哪種策略。

也許第一次嘗試全球信任度調查報告,如果結果是不夠好,儘量StrategyTwo ...

命令是必然的需要發生像TryToWalkAcrossTheRoomCommand不同的東西。只要某個物體試圖穿過房間,此命令就會被觸發,但在其內部,它可能會嘗試使用StrategyOne和StrategyTwo來嘗試穿過房間。

馬克

+2

RE:「做同樣事情的多種方式」 - 這似乎與一些常見戰略案例相沖突。特別是那些有加法,減法,乘法等實現類的人。也許這些都不是很好的例子? – 2011-07-18 16:45:50

+1

@JoshuaDavis所有這些「基準」都是一種策略的特例:*算術運算*。它們有共同的參數(2個操作數)併產生一個值作爲結果。幾乎相同的做法(作爲blackboxes)是他們自己不同的方式,取決於實施。所以我看到這裏沒有衝突,但是,恰恰相反:很好的例子=) – 2016-03-01 00:09:58

48

戰略封裝算法。命令將發送者與請求的接收者分開,他們將請求轉變爲對象。

如果它是一種算法,將如何做,使用一個策略。如果您需要將方法的調用與其執行分離,請使用Command。當您將消息排隊等待以後使用時,通常會使用命令,如任務或事務。

+0

有道理http://en.wikipedia.org/wiki/Command_Pattern客戶端和調用者綁定,但同時,他們不知道彼此! – 2012-05-11 22:14:00

7

我認爲我可能是錯的,但我把command當作函數執行或反應。應該至少有兩個參與者:請求行動的人和執行行動的人。 GUI是命令模式的典型示例:

  • 應用程序工具欄上的所有按鈕都與一些操作相關聯。
  • 按鈕是這種情況下的執行者。
  • 在這種情況下,動作是命令。

的命令通常限定在一定範圍或業務領域,但不是必需的:你可能有這個問題的法案命令,啓動火箭或一個內刪除實現相同的接口文件(如單​​法)應用。通常命令是自包含的,所以它們不需要執行者的任何東西來處理他們打算的任務(所有必要的信息都是在構建時給出的),有時命令是上下文敏感的,並且應該能夠發現這個上下文(退格命令應該知道文本中的插入位置以正確刪除以前的字符; 回滾命令應該發現當前要回滾的事務; ...)。

strategy有點不同:它更多地侷限於某個區域。該策略可以定義一個規則來格式化日期(以UTC?locale特定?)(「日期格式化程序」策略)或計算幾何圖形的平方(「平方計算器」策略)。從這個意義上說,策略就是輕量級對象,它將某些東西當作輸入(「日期」,「圖形」......)並在其基礎上作出一些決定。也許不是最好的,但策略的一個好例子是與javax.xml.transform.Source接口相關的一個:根據傳遞的對象是DOMSource還是SAXSourceStreamSource策略(在本例中= XSLT變換器)將應用不同的規則來處理它。實施可以是簡單的switch或涉及Chain of responsibility pattern

但確實在這兩種模式之間有一些共同之處:命令和策略將算法封裝在相同的語義區域內。

+1

*我將該命令視爲回調函數或反應。應該至少有兩個玩家:一個請求行動,一個執行...... * - 我明白你想說什麼,但我不願意使用「回叫」這個詞,因爲通常單詞「回調」意味着一個異步調用,您不需要爲命令模式進行異步調用就可以使用。例如:Microsoft Word。工具欄按鈕點擊和快捷鍵不會調用異步命令,但我們可以理解如何在這種情況下命令模式將會有用 – 2011-01-04 22:51:55

+0

我同意,儘管Jim表示我會編輯以刪除對回調的引用。 – JamesC 2012-04-05 09:13:55

+0

謝謝,我做了一些擴展。讓我知道,如果你同意/不同意。 – 2012-04-05 13:16:11

22

回答一個非常古老的問題。 (是否有人看到最新的答案,而不是最多的投票?)

這是一個有效的混淆,因爲有相似之處。策略和命令模式均使用封裝。但是這並不會使它們變得一樣。

關鍵的區別是瞭解封裝什麼。 OO原則,這兩種模式都依賴於,封裝什麼變化

在策略的情況下,有什麼變化是算法。例如,一個策略對象知道如何輸出到XML文件,而另一個輸出到JSON。保持不同的算法(封裝)在不同的類。它是如此簡單。

在命令的情況下,變化的是請求本身。請求可能來自File Menu > DeleteRight Click > Context Menu > DeleteJust Delete Button pressed。所有這三種情況都可以生成3個相同類型的命令對象。這些命令對象只代表3個刪除請求;不是刪除算法。由於請求現在是一堆對象,我們可以輕鬆管理它們。突然間,提供撤銷或重做等功能變得微不足道。

命令如何實現請求的邏輯並不重要。在調用execute()時,它可以實現一個觸發刪除的算法,甚至可以委託給其他對象,甚至可以委託給一個策略。這只是命令模式的實現細節。這就是爲什麼它被命名爲命令雖然它不是一種禮貌的方式來要求: - )

與戰略對比它;這種模式只關心執行的實際邏輯。如果我們這樣做,有助於以最少的一組類來實現行爲的不同組合,從而防止課堂爆炸。

我認爲,Command可以幫助我們擴大對封裝的理解,而Strategy提供封裝和多態的自然使用。

3

命令:

基本組成:

  1. 命令聲明瞭抽象的命令,如​​
  2. 接收機接口知道如何執行特定命令
  3. 祈求保持的ConcreteCommand,其具有要被執行
  4. 客戶創建的ConcreteCommand和分配接收機
  5. 的ConcreteCommand定義在Co mmand接收機

工作流程:

客戶調用祈求 =>祈求調用的ConcreteCommand =>的ConcreteCommand呼叫接收機方法,它實現抽象命令方法。

優點:客戶端不受影響命令和接收器的變化。 Invoker在客戶端和Receiver之間提供鬆耦合。您可以使用相同的Invoker運行多個命令。

命令模式允許您使用相同祈求執行不同接收機的命令。祈求是不知道的接收機

型爲了更好地理解概念,具有通過的Pankaj庫馬爾除了維基百科的鏈接看看這個JournalDev article和dzone article通過詹姆斯Sugrue

您可以使用命令模式

  1. 解耦調用命令的&接收機

  2. 實施回撥機制

  3. 實現撤消和重做功能

  4. 維護命令的歷史

java.lang.Thread是一個良好的實施命令格局。你可以把主題作爲調用&類實現Runnable接口ConcreteCommonad /接收器run()方法命令。命令模式的

撤銷/重做的版本可以在西奧多·諾維爾的article

戰略閱讀:

策略模式是非常簡單易懂。

您有一個算法的多個實現,算法的實現可以在運行時根據特定條件更改。

採取航空訂票系統的票價組成的一個例子

航空公司願意提供不同時段不同票價 - 高峯期和非高峯期。在非高峯期旅行時,它希望通過提供有吸引力的折扣刺激需求。

關鍵要點戰略模式:

  1. 這是一種行爲模式
  2. 它基於代表團
  3. 它通過修改
  4. 它使用方法的行爲改變對象的膽量在算法家族之間切換
  5. 它改變對象在運行時間

相關文章與代碼示例:

Using Command Design pattern

Real World Example of the Strategy Pattern

0

對於我來說,不同的是意圖之一。這兩個模式的實現是非常相似的,但有不同的用途:

  • 對於一個策略,使用對象的組件知道對象做什麼(並用它來執行自己的工作的一部分),但它不在乎它如何它。

  • 對於一個命令,使用對象的組件既不知道命令做什麼也不如何做它 - 它只是知道如何調用它。調用者的任務就是運行命令 - 由命令執行的處理不構成調用者的核心工作的一部分。

這是不同之處 - 使用組件的對象是否真的知道或關心組件的功能?大多數情況下,這可以根據模式對象是否向其調用者返回值來確定。如果調用者關心模式對象的作用,那麼它可能會希望它返回一些東西,這將是一個策略。如果它不關心任何返回值,它可能是一個Command(注意,像Java Callable這樣的東西仍然是一個Command,因爲雖然它返回一個值,但調用者並不在意這個值 - 它只是將它傳遞回來到最初提供命令的任何東西)。