命令模式(Command)

本文參考自:《JAVA設(shè)計(jì)模式》之命令模式(Command)

1. 作用

命令模式屬于對(duì)象的行為模式翩伪。命令模式又稱為行動(dòng)(Action)模式或交易(Transaction)模式碰凶。

命令模式把一個(gè)請(qǐng)求或者操作封裝到一個(gè)對(duì)象中钳榨。命令模式允許系統(tǒng)使用不同的請(qǐng)求把客戶端參數(shù)化,對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,可以提供命令的撤銷和恢復(fù)功能购对。

2. 結(jié)構(gòu)
命令模式結(jié)構(gòu)

其中有四個(gè)主要角色

  • 命令角色(Command)
    所有命令類的抽象接口
  • 具體命令角色(ConcreteCommand)
    定義一個(gè)接收者和行為之間的弱耦合啡浊;實(shí)現(xiàn)execute()方法戳粒,負(fù)責(zé)調(diào)用接收者的相應(yīng)操作。execute()方法通常叫做執(zhí)行方法虫啥。
  • 請(qǐng)求者角色(Invoker)
    負(fù)責(zé)調(diào)用命令對(duì)象執(zhí)行請(qǐng)求蔚约,相關(guān)的方法叫做行動(dòng)方法。
  • 接收者角色(Receiver)
    負(fù)責(zé)具體實(shí)施和執(zhí)行一個(gè)請(qǐng)求涂籽。任何一個(gè)類都可以成為接收者苹祟,實(shí)施和執(zhí)行請(qǐng)求的方法叫做行動(dòng)方法。
3. 具體實(shí)現(xiàn)

Receiver

public class Receiver {
    
    public void action() {
        System.out.println("action");
    }
}

Command

public interface Command {
    void execute();
}

ConcreteCommand

public class ConcreteCommand implements Command{
    private Receiver receiver;
    
    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }
    
    @Override
    public void execute() {
        receiver.action();
    }

}

Invoker

public class Invoker {
    private Command command;
    public Invoker(Command command) {
        this.command = command;
    }
    
    public void invoke() {
        command.execute();
    }
}

具體實(shí)現(xiàn)

public class CommandPatternMain {

    public static void main(String[] args) {
        
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
        Invoker invoker = new Invoker(command);
        
        invoker.invoke();

    }

}
4. 命令模式實(shí)例-AudioPlayer系統(tǒng)

小女孩茱麗(Julia)有一個(gè)盒式錄音機(jī),此錄音機(jī)有播音(Play)树枫、倒帶(Rewind)和停止(Stop)功能直焙,錄音機(jī)的鍵盤便是請(qǐng)求者(Invoker)角色;茱麗(Julia)是客戶端角色砂轻,而錄音機(jī)便是接收者角色奔誓。Command類扮演抽象命令角色,而PlayCommand搔涝、StopCommand和RewindCommand便是具體命令類厨喂。茱麗(Julia)不需要知道播音(play)、倒帶(rewind)和停止(stop)功能是怎么具體執(zhí)行的庄呈,這些命令執(zhí)行的細(xì)節(jié)全都由鍵盤(Keypad)具體實(shí)施蜕煌。茱麗(Julia)只需要在鍵盤上按下相應(yīng)的鍵便可以了。

錄音機(jī)是典型的命令模式诬留。錄音機(jī)按鍵把客戶端與錄音機(jī)的操作細(xì)節(jié)分割開來斜纪。

AudioPlayer系統(tǒng)

被調(diào)用者,AudioPlayer

public class AudioPlayer {
    
    public void play() {
        System.out.println("play");
    }
    
    public void replay() {
        System.out.println("replay");
    }
    
    public void pause() {
        System.out.println("pause");
    }
    
    public void stop() {
        System.out.println("stop");
    }
}

抽象命令

public interface Command {
    void execute();
}

具體的命令

public class PlayCommand implements Command{
    
    private AudioPlayer audioPlayer;
    
    public PlayCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }
    
    @Override
    public void execute() {
        audioPlayer.play();
    }

}
public class ReplayCommand implements Command{
    
    private AudioPlayer audioPlayer;
    
    public ReplayCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }
    
    @Override
    public void execute() {
        audioPlayer.replay();
    }
}
public class PauseCommand implements Command{
    
    private AudioPlayer audioPlayer;
    
    public PauseCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }
    
    @Override
    public void execute() {
        audioPlayer.pause();
    }
}
public class StopCommand implements Command{
    
    private AudioPlayer audioPlayer;
    
    public StopCommand(AudioPlayer audioPlayer) {
        this.audioPlayer = audioPlayer;
    }
    
    @Override
    public void execute() {
        audioPlayer.stop();
    }
}

調(diào)用者 Invoker

public class AudioPlayerInvoker {
    
    private PlayCommand playCommand;
    private ReplayCommand replayCommand;
    private PauseCommand pauseCommand;
    private StopCommand stopCommand;
    
    public void setPlayCommand(PlayCommand playCommand) {
        this.playCommand  = playCommand;
    }
    
    public void setReplayCommand(ReplayCommand replayCommand) {
        this.replayCommand = replayCommand;
    }
    
    public void setPauseCommand(PauseCommand pauseCommand) {
        this.pauseCommand = pauseCommand;
    }
    
    public void setStopCommand(StopCommand stopCommand) {
        this.stopCommand = stopCommand;
    }
    
    public void play() {
        playCommand.execute();
    }
    
    public void replay() {
        replayCommand.execute();
    }
    
    public void pause() {
        pauseCommand.execute();
    }
    
    public void stop() {
        stopCommand.execute();
    }
    
    
}

具體實(shí)現(xiàn)

public class NormalCommandPatternDemoMain {

    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();
        
        PlayCommand playCommand = new PlayCommand(audioPlayer);
        ReplayCommand replayCommand = new ReplayCommand(audioPlayer);
        PauseCommand pauseCommand = new PauseCommand(audioPlayer);
        StopCommand stopCommand = new StopCommand(audioPlayer);
        
        AudioPlayerInvoker invoker = new AudioPlayerInvoker();
        invoker.setPlayCommand(playCommand);
        invoker.setReplayCommand(replayCommand);
        invoker.setPauseCommand(pauseCommand);
        invoker.setStopCommand(stopCommand);
        
        invoker.play();
        invoker.replay();
        invoker.pause();
        invoker.stop();
    }

}
5. 宏命令模式

所謂宏命令簡單點(diǎn)說就是包含多個(gè)命令的命令文兑,是一個(gè)命令的組合盒刚。

設(shè)想茱麗的錄音機(jī)有一個(gè)記錄功能,可以把一個(gè)一個(gè)的命令記錄下來绿贞,再在任何需要的時(shí)候重新把這些記錄下來的命令一次性執(zhí)行伪冰,這就是所謂的宏命令集功能。因此樟蠕,茱麗的錄音機(jī)系統(tǒng)現(xiàn)在有四個(gè)鍵贮聂,分別為播音、倒帶寨辩、停止和宏命令功能吓懈。此時(shí)系統(tǒng)的設(shè)計(jì)與前面的設(shè)計(jì)相比有所增強(qiáng),主要體現(xiàn)在Julia類現(xiàn)在有了一個(gè)新方法靡狞,用以操作宏命令鍵耻警。


宏命令模式

在上面例子的基礎(chǔ)上,增加和修改的部分
MacroCommand 宏命令接口

public interface MacroCommand extends Command{
    void add(Command command);
    void remove(Command command);
}

ConcreteMacroCommand 宏命令接口的具體實(shí)現(xiàn)

public class MacroAudioCommand implements MacroCommand{
    
    private List<Command> commandList;
    
    public MacroAudioCommand() {
        commandList = new ArrayList<>();
    }
    @Override
    public void add(Command command) {
        commandList.add(command);
    }
    
    @Override
    public void remove(Command command) {
        commandList.remove(command);
    }
    
    @Override
    public void execute() {
        for(Command command:commandList) {
            command.execute();
        }
    }
}

AudioPlayerInvoker的修改

public class AudioPlayerInvoker {

    private MacroAudioCommand macroAudioCommand;
    
    public AudioPlayerInvoker() {
        macroAudioCommand = new MacroAudioCommand();
    }
    
    public void add(Command command) {
        macroAudioCommand.add(command);
    }
    
    public void remove(Command command) {
        macroAudioCommand.remove(command);
    }
    
    public void invoke() {
        macroAudioCommand.execute();
    }
}

具體實(shí)現(xiàn)部分的修改

public class MacroCommandPatternDemoMain {

    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();
        
        PlayCommand playCommand = new PlayCommand(audioPlayer);
        ReplayCommand replayCommand = new ReplayCommand(audioPlayer);
        PauseCommand pauseCommand = new PauseCommand(audioPlayer);
        StopCommand stopCommand = new StopCommand(audioPlayer);
        
        AudioPlayerInvoker invoker = new AudioPlayerInvoker();
        invoker.add(playCommand);
        invoker.add(replayCommand);
        invoker.add(pauseCommand);
        invoker.add(stopCommand);
        
        invoker.invoke();

    }

}

6. 命令模式的優(yōu)點(diǎn)

(1)命令模式使新的命令很容易地被加入到系統(tǒng)里甸怕。

(2)允許接收請(qǐng)求的一方?jīng)Q定是否要否決請(qǐng)求甘穿。

(3)能較容易地設(shè)計(jì)一個(gè)命令隊(duì)列。

(4)可以容易地實(shí)現(xiàn)對(duì)請(qǐng)求的撤銷和恢復(fù)梢杭。

(5)在需要的情況下温兼,可以較容易地將命令記入日志。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末武契,一起剝皮案震驚了整個(gè)濱河市募判,隨后出現(xiàn)的幾起案子荡含,更是在濱河造成了極大的恐慌,老刑警劉巖届垫,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件释液,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡装处,警方通過查閱死者的電腦和手機(jī)误债,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妄迁,“玉大人寝蹈,你說我怎么就攤上這事∨凶澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵项戴,是天一觀的道長形帮。 經(jīng)常有香客問我,道長周叮,這世上最難降的妖魔是什么辩撑? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮仿耽,結(jié)果婚禮上合冀,老公的妹妹穿的比我還像新娘。我一直安慰自己项贺,他們只是感情好君躺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著开缎,像睡著了一般棕叫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奕删,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天俺泣,我揣著相機(jī)與錄音,去河邊找鬼完残。 笑死伏钠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谨设。 我是一名探鬼主播熟掂,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼扎拣!你這毒婦竟也來了打掘?” 一聲冷哼從身側(cè)響起华畏,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尊蚁,沒想到半個(gè)月后亡笑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡横朋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年仑乌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琴锭。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晰甚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出决帖,到底是詐尸還是另有隱情厕九,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布地回,位于F島的核電站扁远,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏刻像。R本人自食惡果不足惜畅买,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望细睡。 院中可真熱鬧谷羞,春花似錦、人聲如沸溜徙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蠢壹。三九已至雁歌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間知残,已是汗流浹背靠瞎。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留求妹,地道東北人乏盐。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像制恍,于是被迫代替她去往敵國和親父能。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355