设计模式——命令模式(遥控器与灯)

本文首发于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与模式》之命令模式
相关文章
相关标签/搜索