設計模式——命令模式(遙控器與燈)

本文首發於cdream的我的博客,點擊得到更好的閱讀體驗!html

歡迎轉載,轉載請註明出處。java

本文主要對命令模式進行概述講解,並使用使用遙控器與燈來說述命令模式中調用者與接收者的關係。git

image-20181213000538037

<!--more-->github

1、概述

命令模式(英語:Command pattern)是一種設計模式,它嘗試以對象來表明實際行動。命令對象能夠把行動(action) 及其參數封裝起來,因而這些行動能夠被重複使用、撤銷、撤銷後重作。設計模式

這個是概念是來自維基百科,我以爲最容易理解,就是把命令封裝成對象,使命令能夠重複調用、撤銷,下降了調用者和接受者的耦合,同時容易擴展出新的命令。多線程

<div class="note"><strong>其餘描述</strong>:<br>1.將「請求」封裝成對象,以便使不一樣的請求、隊列或日誌來參數化其餘對象,命令模式也支持可撤銷操做。(Head First 設計模式)<br>2.命令模式把一個請求或者操做封裝到一個對象中。命令模式容許系統使用不一樣的請求把客戶端參數化,對請求排隊或者記錄請求日誌,能夠提供命令的撤銷和恢復功能。(Java與模式)</div>ide

你們作適當參考,不理解能夠先看看下面的源碼!this

2、結構

如圖,這是命令模式的結構:spa

image-20181212211929846

以用遙控器開燈爲例(Head First 設計模式例子)線程

  • Invoker:命令調用者,負責調用命令對象的請求——遙控器

  • Command:聲明瞭一個具體命令類實現的接口——命令的接口

  • ConcreteCommand:具體命令,實現了Invoker和Receiver之間的解耦,一般持有接收者對象的飲用——開燈按鈕執行的命令

  • Receiver:命令接收者,真正接收命令並執行動做的對象——

  • Client:客戶端,創造具體的命令,並肯定接收者

3、源代碼

Receiver——二檔亮度的燈

// 二檔調節的燈,在這裏做爲接收者
public class Light {
    public static final String HIGH = "賊亮";

    public static final String MEDIUM = "有點亮";

    public static final String LOW = "快滅火了";

    public static final String OFF = "真的滅火了~";

    private String luminance;

    public Light() {
        this.luminance = OFF;
    }

    public void off() {
        System.out.println("燈關閉了");
        this.luminance = OFF;
    }

    public void high() {
        System.out.println("賊亮");
        this.luminance = HIGH;
    }

    public void medium() {
        System.out.println("挺亮地!");
        this.luminance = MEDIUM;
    }

    public void low() {
        System.out.println("快滅火了");
        this.luminance = LOW;
    }
    
    public String getLuminance(){
        return this.luminance;
    }
}

Command——作個命令接口,帶撤銷功能

public interface Command {
    void excute();
    void undo();
}

LightHighCommand——高光命令

public class LightHighCommand implements Command {
    private Light light;
    private String preLuminance;
    @Override
    public void excute() {
        // 備份上一個命令,撤銷使用
        preLuminance = light.getLuminance();
        light.high();
    }

    @Override
    public void undo() {
        if (Light.HIGH.equals(preLuminance)){
            light.high();
        }else if(Light.MEDIUM.equals(preLuminance) ){
            light.medium();
        }else if (Light.LOW.equals(preLuminance)){
            light.low();
        }else if (Light.OFF.equals(preLuminance)){
            light.off();
        }
    }

    public LightHighCommand(Light light) {
        this.light = light;
    }
    // 智能遙控器按鍵功能能夠控制多個燈
    // 若是控制令一個接收者,能夠傳入,不用新建命令
    public void setLight(Light light) {
        this.light = light;
    }
}

LightOffCommand——關燈命令

public class LightOffCommand implements Command {
    private Light light;
    private String preLuminance;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void excute() {
        preLuminance = light.getLuminance();
        light.off();
    }

    @Override
        public void undo() {
            if (Light.HIGH.equals(preLuminance)){
                light.high();
            }else if(Light.MEDIUM.equals(preLuminance) ){
                light.medium();
            }else if (Light.LOW.equals(preLuminance)){
                light.low();
            }else if (Light.OFF.equals(preLuminance)){
                light.off();
            }
        }
    
    public void setLight(Light light) {
        this.light = light;
    }
}

Invoker——遙控器

public class RemoteControl {
    private Command off;
    private Command high;
    private Command medium;
    private Command low;
    private Command preCommand;

    public void setOff(Command off) {
        this.off = off;

    }

    public void setHigh(Command high) {
        this.high = high;
    }

    public void setMedium(Command medium) {
        this.medium = medium;
    }

    public void setLow(Command low) {
        this.low = low;

    }

    public void lightOff() {
        off.excute();
        preCommand = off;
    }

    public void lightHigh() {
        high.excute();
        preCommand = high;

    }

    public void lightMedium() {
        medium.excute();
        preCommand = medium;

    }

    public void lightLow() {
        low.excute();
        preCommand = low;
    }

    public void undo() {
        if (preCommand == null) {
            System.out.println("沒法撤銷");
        } else {
            preCommand.undo();
        }
    }
}

Client——客戶端

public class Client {
    public static void main(String[] args) {
        // 建立接收者
        Light light = new Light();
        // 建立命令
        Command lightHighCommand = new LightHighCommand(light);
        Command lightOffCommand = new LightOffCommand(light);
        // 建立調用者
        RemoteControl remoteControl = new RemoteControl();
        remoteControl.setHigh(lightHighCommand);
        remoteControl.setOff(lightOffCommand);
        // 調用
        remoteControl.lightHigh();
        remoteControl.lightOff();
        remoteControl.undo();
    }
}

————————>結果
賊亮
燈關閉了
賊亮

以上就是一個帶撤回功能的命令模式,其中:

若是想實現多步撤回,能夠考慮把調用者中的preCommand換成stack;

若是想實現組合命令,能夠從新建立一個宏命令,以下

public class MacroCommand implements Command {
    private Command[] commands;

    public MacroCommand(Command[] commands) {
        this.commands = commands;
    }

    @Override
    public void excute() {
        for (Command command : commands) {
            command.excute();
        }
    }

    @Override
    public void undo() {
        for (Command command : commands) {
            command.undo();
        }
    }
}

你能夠用這個命令實現任何形式的命令組合,甚至若是你以爲你的遙控器能夠控制空調,控制電源,控制電飯鍋,你甚至能夠把這些命令組合進來~

4、命令模式的優缺點

優勢

  • 解耦合:將命令調用者和命令執行者經過命令進行解耦,命令調用者不關心由誰來執行命令,只要命令執行就能夠

  • 更動態的控制:請求被封裝成對象後,能夠輕易的參數化、隊列化、日誌化,使系統更加靈活。

  • 更容易的命令組合:有了宏命令後,能夠任意的對命令進行組合

  • 更好擴展性:能夠輕易的添加新的命令,並不會影響到其餘的命令

缺點

  • 命令過多時,會建立了過多的命令類,不方便進行管理

5、總結

本文對命令模式做了簡單的介紹,命令模式只要明白調用者如何經過命令與接收者交互,就比較好理解。在實際應用中,命令模式能夠用在並行處理、事務行爲、線程池等地方。例如傳統的線程池就有addTask()方法將命令加入到等待被執行的隊列中,容許多線程執行實現java.lang.Runnable 的命令,儘管線程池自己對具體的任務毫無認知。


  1. Head First 設計模式,Eric Freeman &Elisabeth Freeman with Kathy Sierra & Bert Bates
  2. Command pattern,wiki
  3. 《JAVA與模式》之命令模式
相關文章
相關標籤/搜索