Head First設(shè)計模式---命令模式

定義

將請求封裝成對象,這可以讓你使用不同的請求,隊列,或者日志請求來參數(shù)化其他對象。命令模式也可以支持撤銷操作。

例子

現(xiàn)在需要做一個遙控器,遙控器上有很多按鈕,每一個按鈕對應(yīng)一個功能,比如開燈,開電視等。

注: 需要考慮遙控器未來可能發(fā)生的擴展與變化。

分析

我們可能有以下思路:

1.創(chuàng)建一個遙控器對象,這個對象有多個按鈕,每個按鈕都綁定一個方法,對于每一個按鈕按下的時候,調(diào)用綁定的方法即可。

- (void)actionOfButton1 {
    light = new Light();
    light.on();
}

- (void)actionOfButton2 {
    tv = new TV();
    tv.on();
}

...

分析:這種做法直觀有效。在一些場景下,也是不錯的方法。其實沒有必要盲目使用設(shè)計模式,有些場景,用簡單直觀的方式完成需求,也沒什么問題,主要是要根據(jù)實際需求來使用?;氐竭@個例子,遙控器在以后版本的迭代中,很可能不斷增加按鈕,可能交互按鈕的功能,比如把第二個按鈕的功能放到第一個按鈕等。這些情況,我們就需要不斷修改遙控器對象,這會造成潛在的錯誤。

注意:這里需要注意設(shè)計模式中兩個重要的設(shè)計原則:

類應(yīng)該對擴展開放,對修改關(guān)閉。

為交互對象之間的松耦合設(shè)計而努力。

這里擴展和修改的意思,我的理解是修改是更改了已有方法的邏輯,而擴展是指增加了新的方法。

2.看到上面的問題,進一步的想法, 不再將遙控器的按鈕方法寫死,而是提供一個接口setAction來配置:

    remoteControl = new RemoteControl();
    remoteControl.setAction(button1, action1);

分析:和方案一相比,我們只是將按鈕操作的內(nèi)容提取為一個對象,然后作為參數(shù)傳遞給遙控器。如果增加按鈕,也只需要新建新的動作,然后調(diào)用setAction到某一個按鈕。如果需要交互兩個按鈕的功能,直接通過setAction就可以了。

不知不覺中,我們就用到了命令模式。我們將發(fā)出請求的接受者(light,tv等)和執(zhí)行動作(on, off等)封裝為一個命令對象(即上文中action對象)。實際上,這是個“聰明”命令對象,很多場景下,這么設(shè)計也完全ok。只是調(diào)用者和接收者的解耦程度不如“傻瓜”命令對象。所謂“傻瓜”命令對象,它只調(diào)用接受者的方法,不關(guān)心方法的細節(jié)。其實主要區(qū)別就在于是否將實際工作委托給接受者?!吧倒稀泵顚ο筮€可以不關(guān)注接受者,將接受者作為參數(shù)傳遞,接受者只需要實現(xiàn)一個約定的接口。

Coding time

命令模式類圖

實現(xiàn)命令接口

接口是指一系列方法的聲明,這些方法不用具體實現(xiàn),可以在不同的類中有不同的實現(xiàn)。在這里,我們需要定義一個命令接口,接口需要實現(xiàn)execute的方法:

  @protocol CommandInterface <NSObject>

  @required

  - (void)execute;

  @end

實現(xiàn)命令

一個具體的命令需要實現(xiàn)命令接口:

@class Light;

@interface LightOnCommand : NSObject<CommandInterface>

@end
@implementation LightOnCommand

- (void)execute {
   [_light on];
}
@end

實現(xiàn)控制器

@implementation SimpleRemoteControl

- (void)setCommand:(id<CommandInterface>)command {
    _slot = command;
}

- (void)buttonWasPressed {
    if ([_slot respondsToSelector:@selector(execute)]) {
        [_slot execute];
    }
}
@end

使用

Light *light = [Light new];
LightOnCommand *lightOnCommand = [[LightOnCommand alloc] initWithLight:light];

SimpleRemoteControl *control = [SimpleRemoteControl new];
[control setCommand:lightOnCommand];

[control buttonWasPressed];

這就完成了一個簡單的命令模式,可以嘗試著增加新的命令,會發(fā)現(xiàn)這樣是符合修改擴展原則的

總結(jié)

  • 命令模式將發(fā)出請求的對象和執(zhí)行請求的對象解耦
  • 在被解耦的兩者之間是通過命令對象進行溝通的。命令對象封裝了接受者和一個或一組動作
  • 調(diào)用者通過調(diào)用命令對象的execute發(fā)出請求,這會使得接受者的動作被調(diào)用
  • 調(diào)用者可以接受命令當(dāng)做參數(shù),甚至在運行時動態(tài)的進行
  • 命令對象可以支持撤銷,做法是實現(xiàn)一個undo方法來回到execute執(zhí)行前的狀態(tài)
  • 實際操作時,很常見使用“聰明”命令對象,也就是直接實現(xiàn)了請求,而不是將工作委托給接收者
  • 命令也可以用來實現(xiàn)日志和事務(wù)系統(tǒng)

代碼下載

https://github.com/wszxy/DesignPattern

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 設(shè)計模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,890評論 0 14
  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,211評論 3 119
  • 夜市婦 暖睡榻中夜難眠,腹饑輾轉(zhuǎn)懶推軒。 開窗北風(fēng)狼猿吼,長街冷冷星點煙。 抬眼霜月掛高閣,俯耳醉漢罵路邊。 扎鞋...
    長安舊人閱讀 407評論 10 11
  • 拾七月閱讀 380評論 0 3
  • N姐是朋友的同事。住朋友隔壁宿舍。 去年秋天,她突然搬出宿舍,聽說她買房了。 這絕對震驚到小伙伴們了。 她才工作兩...
    禾豆閱讀 954評論 0 2

友情鏈接更多精彩內(nèi)容