天天看點

指令模式

指令模式

Command Pattern

是一種資料驅動的設計模式,其屬于行為型模式,别名為動作

Action

模式或事務

Transaction

模式,指令模式将請求以指令的形式包裹在對象中,并傳給調用對象,調用對象尋找可以處理該指令的合适的對象,并把該指令傳給相應的對象,該對象對請求排隊或者記錄請求日志,以及支援可撤銷的操作。

描述

在軟體設計中,我們經常需要向某些對象發送請求,但是并不知道請求的接收者是誰,也不知道被請求的操作是哪個,我們隻需在程式運作時指定具體的請求接收者即可,此時,可以使用指令模式來進行設計,使得請求發送者與請求接收者消除彼此之間的耦合,讓對象之間的調用關系更加靈活。指令模式可以對發送者和接收者完全解耦,發送者與接收者之間沒有直接引用關系,發送請求的對象隻需要知道如何發送請求,而不必知道如何完成請求。指令模式也可以用于實作基于事務的系統,一旦執行指令,便會繼續保留指令的曆史記錄,如果最終指令成功執行,那麼一切都很好,否則隻需周遊曆史記錄并繼續對所有已執行的指令執行撤消即可。

優點

  • 降低系統的耦合度。
  • 新的指令可以很容易地加入到系統中。
  • 可以比較容易地設計一個指令隊列和宏指令(組合指令)。
  • 可以友善地實作對請求的Undo和Redo。

缺點

  • 使用指令模式可能會導緻某些系統有過多的具體指令類。因為針對每一個指令都需要設計一個具體指令類,是以某些系統可能需要大量具體指令類,這将影響指令模式的使用。

适用環境

  • 系統需要将請求調用者和請求接收者解耦,使得調用者和接收者不直接互動。
  • 系統需要在不同的時間指定請求、将請求排隊和執行請求。
  • 系統需要支援指令的撤銷

    Undo

    操作和恢複

    Redo

    操作。
  • 系統需要将一組操作組合在一起,即支援宏指令

實作

// 假設我們有一個電燈,我們使用遙控器對其進行控制

class Bulb {
    turnOn() {
        console.log("Bulb has been lit!");
    }
    
    turnOff() {
        console.log("Darkness!");
    }
}

class Command {
    execute(){
        throw new Error("Abstract method cannot be called");
    }

    redo(){
        throw new Error("Abstract method cannot be called");
    }

    undo(){
        throw new Error("Abstract method cannot be called");
    }
}

class TurnOnCommand extends Command{
    constructor(bulb) {
        super();
        this.bulb = bulb;
    }
    
    execute() {
        this.bulb.turnOn();
    }
    
    undo() {
        this.bulb.turnOff();
    }
    
    redo() {
        this.execute();
    }
}

class TurnOffCommand extends Command {
    constructor(bulb) {
        super();
        this.bulb = bulb;
    }
    
    execute() {
        this.bulb.turnOff();
    }
    
    undo() {
        this.bulb.turnOn();
    }
    
    redo() {
        this.execute();
    }
}

class RemoteControl {
    submit(command) {
        command.execute();
    }
}

(function(){
    var bulb = new Bulb();

    var turnOn = new TurnOnCommand(bulb);
    var turnOff = new TurnOffCommand(bulb);

    var remote = new RemoteControl();
    remote.submit(turnOn); // Bulb has been lit!
    remote.submit(turnOff); // Darkness!
})();
           

每日一題

https://github.com/WindrunnerMax/EveryDay
           

參考

https://www.runoob.com/design-pattern/command-pattern.html
https://github.com/sohamkamani/javascript-design-patterns-for-humans#-command
https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html