Java 设计模式中的命令模式详情

目录
  • 模式介绍
  • UML类图
  • 命令模式案例
  • 命令模式的注意事项和细节

模式介绍

  • 命令模式(Command Pattern) :在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计。
  • 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
  • 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。

UML类图

类图解析:

  • Invoker:是调用者角色。
  • Command:是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
  • ConcreteCommand:将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现execute、undo方法
  • Receiver:接受者角色,知道如何实施和执行一个请求相关的操作

命令模式案例

案例解析:智能家居,通过一个遥控器控制家里的智能设备

Command接口类

public interface Command {

    /**
     * 执行操作
     */
    void execute();

    /**
     * 撤销操作
     */
    void undo();
}

LightReceiver、CurtainReceiver信号接收者

public class LightReceiver {

    public void on() {
        System.out.println("开灯...");
    }
    public void off() {
        System.out.println("关灯....");
    }
}
public class CurtainReceiver {
    public void on() {
        System.out.println("打开窗帘...");
    }

    public void off() {
        System.out.println("关闭窗帘...");
    }
}

Command具体实现子类CurtainOnCommand、CurtainOffCommand、LightOnCommand、LightOffCommand、NoCommand

public class CurtainOnCommand implements Command {
    private CurtainReceiver curtain;

    public CurtainOnCommand(CurtainReceiver curtainReceiver) {
        this.curtain = curtainReceiver;
    }

    @Override
    public void execute() {
        curtain.on();
    }

    @Override
    public void undo() {
        curtain.off();
    }
}
public class CurtainOffCommand implements Command {
    private CurtainReceiver curtainReceiver;

    public CurtainOffCommand(CurtainReceiver curtainReceiver) {
        this.curtainReceiver = curtainReceiver;
    }

    @Override
    public void execute() {
        curtainReceiver.off();
    }

    @Override
    public void undo() {
        curtainReceiver.on();
    }
}
public class LightOnCommand implements Command {
    // 聚合LightReceiver
    private LightReceiver light;

    public LightOnCommand(LightReceiver light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.on();
    }

    @Override
    public void undo() {
        light.off();
    }
}
public class LightOffCommand implements Command {
    // 聚合LightReceiver
    private LightReceiver light;

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

    @Override
    public void execute() {
        light.off();
    }

    @Override
    public void undo() {
        light.on();
    }
}
/**
 * 用于初始化每个按钮
 */
public class NoCommand implements Command {
    @Override
    public void execute() {
        System.out.println("do nothing...");
    }

    @Override
    public void undo() {
        System.out.println("do nothing...");
    }
}

RemoteController调用者

public class RemoteController {
    // 开命令数组
    private Command[] onCommands;
    // 关命令数组
    private Command[] offCommands;

    // 撤销命令位置
    private int no;
    // 撤销命令是否为按下命令
    private Boolean isOn;

    /**
     * 初始化
     */
    public RemoteController() {
        this.onCommands = new Command[5];
        this.offCommands = new Command[5];

        for (int i = 0; i < 5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    /**
     * 设置一行中的按钮
     * @param no
     * @param onCommand
     * @param offCommand
     */
    public void setCommand(int no,Command onCommand,Command offCommand) {
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    /**
     * 开按钮按下
     * @param no
     */
    public void onButtonPushed(int no){
        // 调用按钮方法
        onCommands[no].execute();
        // 记录撤销按钮
        this.no = no;
        isOn = true;
    }

    /**
     * 关按钮按下
     * @param no
     */
    public void offButtonPushed(int no) {
        // 调用按钮方法
        offCommands[no].execute();
        // 记录撤销按钮
        this.no = no;
        isOn = false;
    }

    public void undo() {
        if (isOn) {
            onCommands[no].undo();
        } else {
            offCommands[no].undo();
        }
        isOn = !isOn;
    }
}

Client测试类

public class Client {
    public static void main(String[] args) {
        // 接收者
        LightReceiver lightReceiver = new LightReceiver();
        CurtainReceiver curtainReceiver = new CurtainReceiver();

        // 命令
        Command lightOnCommand = new LightOnCommand(lightReceiver);
        Command lightOffCommand = new LightOffCommand(lightReceiver);
        Command curtainOnCommand = new CurtainOnCommand(curtainReceiver);
        Command curtainOffCommand = new CurtainOffCommand(curtainReceiver);
        // 执行者
        RemoteController remoteController = new RemoteController();
        remoteController.setCommand(0,lightOnCommand,lightOffCommand);
        remoteController.setCommand(1,curtainOnCommand,curtainOffCommand);
        System.out.print("开灯按钮\t");
        remoteController.onButtonPushed(0);
        System.out.print("撤销按钮\t");
        remoteController.undo();
        System.out.print("撤销按钮\t");
        remoteController.undo();
        System.out.print("关灯按钮\t");
        remoteController.offButtonPushed(0);

        System.out.println("------------------");
        System.out.print("开窗帘按钮\t");
        remoteController.onButtonPushed(1);
        System.out.print("撤销按钮 \t");
        remoteController.undo();
        System.out.print("撤销按钮 \t");
        remoteController.undo();
        System.out.print("关窗帘按钮\t");
        remoteController.offButtonPushed(1);
    }
}

测试结果:

个人优化方案(仅供参考):

命令模式的注意事项和细节

  • 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的execute(方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
  • 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令。
  • 容易实现对请求的撤销和重做。
  • 命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意。
  • 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
  • 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟CMD (DOS命令)订单的撤销/恢复、触发-反馈机制
(0)

相关推荐

  • 详解Java设计模式——命令模式

    命令模式 命令模式很好理解,举个例子,司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行.这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的.我们看看关系图: Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象,看实现代码: public interface Com

  • Java设计模式之命令模式_动力节点Java学院整理

    定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 类型:行为类模式 类图: 命令模式的结构 顾名思义,命令模式就是对命令的封装,首先来看一下命令模式类图中的基本结构: Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令. ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现. Client类:最终的客户端调用类.

  • Java设计模式之命令模式详解

    命令模式 定义:将请求封装成对象,这可以让你使用不同的请求.队列.或者日志来参数化其他对象. 何时使用命令模式?当需要将发出请求的对象和执行请求的对象解耦的时候,使用命令模式. 在被解耦的两者之间是通过命令对象进行沟通的.命令对象封装了接收者和一个或一组动作. 调用者通过调用命令对象的execute()方法发出请求,这会使接收者的动作被调用. 调用者可以接收命令当作参数,甚至在运行时动态地进行. 优点: 1.降低了系统耦合度. 2.新的命令可以很容易添加到系统中去. 缺点:使用命令模式可能会导致

  • 23种设计模式(17)java命令模式

    23种设计模式第十七篇:java命令模式 定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 类型:行为类模式 类图: 命令模式的结构 顾名思义,命令模式就是对命令的封装,首先来看一下命令模式类图中的基本结构: Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令. ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现.

  • Java设计模式之java命令模式详解

    目录 命令模式的介绍 角色 订单案例 命令模式的优点 适用场景 示例代码 应用 宏命令----执行一组命令 示例代码 总结 JDK源码解析 Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法 总结 命令模式的介绍 命令模式是对命令的封装.命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象 每一个命令都是一个操作:请求的一方发出请求要求执行一个操作:接收的一方收到请求,并执行操作.命令模式允许请求的一方和接收的一

  • Java以命令模式设计模式

    目录 Java以命令模式设计模式 1.简单介绍 2.命令模式 Java以命令模式设计模式 1.简单介绍 意图: 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化. 主要解决: 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录.撤销或重做.事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适. 何时使用: 在某些场合,比如要对行为进行"记录.撤销/重做.事务"等处理,这种无法抵御变化的紧耦合是不合适的.在这种情况下,如何将

  • 深入理解Java设计模式之命令模式

    目录 一.什么是命令模式 二.命令模式的使用场景 三.命令模式的优缺点 四.命令模式的实现 五.总结 一.什么是命令模式 命令模式是一个高内聚的模式,其定义为:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请 求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 在该类图中,我们看到三个角色: Receiver接受者角色:该角色就是干活的角色,命令传递到这里是应该被执行的 Command命令角色:需要执行的所有命令都在这里声明 Invoker调用者角色:接收到命令,并执行命

  • Java超详细讲解设计模式中的命令模式

    目录 介绍 实现 个人理解:把一个类里的多个命令分离出来,每个类里放一个命令,实现解耦合,一个类只对应一个功能,在使用命令时由另一个类来统一管理所有命令. 缺点:如果功能多了就会导致创建的类的数量过多 命令模式(Command Pattern)是⼀种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调⽤对象.调⽤对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执⾏命令. 介绍 意图:将⼀个请求封装成⼀个对象,从⽽使您可以⽤不同的请求对客户进⾏参数化.

  • Java 设计模式中的命令模式详情

    目录 模式介绍 UML类图 命令模式案例 命令模式的注意事项和细节 模式介绍 命令模式(Command Pattern) :在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计. 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦. 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令

  • 快速理解Java设计模式中的组合模式

    组合模式是一种常见的设计模式(但我感觉有点复杂)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系. 个人理解:组合模式就是将部分组装成整体. 定义如下: 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 通用类图如下: 组合模式的包含角色: ● Component 抽象构件角色 定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. ● Leaf 叶子构件 叶子对象,其下再也没有其他的分支,也就是遍历的最

  • Java设计模式中的外观模式详解

    目录 模式介绍 UML类图 外观模式案例: 外观模式的注意事项和细节 模式介绍 外观模式(Facade) ,也叫“过程模式:外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节. UML类图 类图解析: Facade:为调用端提供统一的调用接口,外观类知道哪些子系统负责处理请求,从而将调用端的请求代理给适当子系统对象

  • Java设计模式中的桥接模式

    目录 模式介绍 UML类图 桥接模式案例 桥接模式的注意事项和细节 常见的应用场景 模式介绍 桥接模式(Bridge模式)是指:将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变. 是一种结构型设计模式. Bridge模式基于类的最小设计原则,通过使用封装.聚合及继承等行为让不同的类承担不同的职责.它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展. UML类图 类图说明: Client类:桥

  • Java设计模式中的门面模式详解

    目录 门面模式 概述 应用场景 目的 优缺点 主要角色 门面模式的基本使用 创建子系统角色 创建外观角色 客户端调用 门面模式实现商城下单 库存系统 支付系统 物流系统 入口系统 客户端调用 门面模式 概述 门面模式(Facade Pattern)又叫外观模式,属于结构性模式. 它提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口.使得子系统更容易使用. 客户端不需要知道系统内部的复杂联系,只需定义系统的入口.即在客户端和复杂系统之间再加一层,这一层

  • Java设计模式中的组合模式

    目录 模式介绍 UML类图 组合模式案例 组合模式的注意事项和细节 模式介绍 组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示“整体_部分”的层次关系. 组合模式依据树形结构来组合对象,用来表示部分以及整体层次. 这种类型的设计模式属于结构型模式. 组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客户以一-致的方式处理个别对象以及组合对象 UML类图 类图解析: Component :这是组合中对象声明接口,

  • Java设计模式中责任链模式详解

    目录 1.责任链设计模式的定义 2.责任链设计模式的优点与不足 3.责任链设计模式的实现思路 4.责任链设计模式应用实例 5.责任链设计模式应用场景 编程是一门艺术,大批量的改动显然是非常丑陋的做法,用心的琢磨写的代码让它变的更美观. 在现实生活中,一个事件需要经过多个对象处理是很常见的场景.例如,采购审批流程.请假流程等.公司员工请假,可批假的领导有部门负责人.副总经理.总经理等,但每个领导能批准的天数不同,员工必须根据需要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名.电话

  • 实例讲解设计模式中的命令模式在iOS App开发中的运用

    命令模式封装一个请求或行为作为一个对象.封装的请求比原的更加灵活,可以在对象之间传递,储存,动态修改,或放入一个队列. 那么让我们简要的说一下命令模式的特点. 它能比较容易地设计一个命令队列: 在需要的情况下,可以较容易地将命令记入日志: 允许接收请求地一方决定是否要否决请求: 可以容易地实现对请求地撤销和重做: 由于加进新地具体命令类不影响其他的类,因此增加新的具体命令类很容易: 把请求一个操作的对象与知道怎么执行一个操作的对象分隔开. 下面给出基本的类结构图: 上面这张图是命令模式的类结构的

  • 详解java设计模式中的门面模式

    门面模式又叫外观模式(Facade Pattern),主要用于隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口. 我们知道电视剧操作很简单,但是里面的设计和原理很少人明白,这就是因为电视剧的设计应用了门面模式 一个电视剧至少需要有以下几个模块的功能:信号输入.音频处理.视频处理.信号输出等 /** * 射频信号输入 */ public class SignalIn { // } * 音频/视频信号输出 public class SignalOut { * 音频处理 public c

随机推荐