前言:

在开发中,我们可能需要向某些对象发送一些请求,但我们不知道请求的具体接收者是谁,也不知道被请求的操作是哪个,只知道在系统运行中指定具体的请求接收者即可,打个比方,电视遥控器,我们只需知道按哪个按钮能够打开电视、关闭电视和换台即可,并不需要知道是怎么开电视、关电视和换台的,对于这种情况,我们可以采用命令模式来进行设计。

一、定义:

命令模式的本质是将请求封装成对象,将发出命令与执行命令的责任分开,命令的发送者和接收者完全解耦,发送者只需知道如何发送命令,不需要关心命令是如何实现的,甚至是否执行成功都不需要理会。命令模式的关键在于引入了抽象命令接口,发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。另外命令可以像强对象一样可以被存储和传递,所以可支持撤销的操作

使用命令模式的优势在于降低了系统的耦合度,而且新命令可以很方便添加到系统中,也容易设计一个组合命令。但缺点在于会导致某些系统有过多的具体命令类,因为针对每一个命令都需要设计一个具体命令类。所以命令模式适用于以下场景:

  • (1)需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • (2)系统需要在不同的时间指定请求、将请求排队和执行请求。
  • (3)系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
  • (4)系统需要将一组操作组合在一起,即支持宏命令。

二、UML结构图:

  • Receiver:接收者,执行命令的对象,任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • Command:抽象命令类,声明需要执行的方法。
  • ConcreteCommand:具体命令类,通常会持有接收者,并调用接收者的功能完成命令要执行的操作。
  • Invoker:调用者,通常会持有命令对象,可以持有多个命令对象,是客户端真正触发命令并要求命令执行相应操作的地方,就是相当于使用命令对象的入口。
  • Client:客户类,创建具体的命令对象,并且设置命令对象的接收者。注意这里不是指常规意义上的客户端,把这个 Client 称为装配者会合适,主要用于组装命令对象和接收者。

三、代码实现:

这里以电视机为例。电视是请求的接受者,遥控器是请求的发送者,遥控器上有一些按钮,不同的按钮对应着不同的操作。在这里遥控器需要执行三个命令:打开电视机、关闭电视机、换台。UML类图如下:

抽象命令类:Command.java

/*** Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它*/
public interface Command {public void execute();
}

电视机类:Television.java

public class Television {public void open(){System.out.println("打开电视机......");}public void close(){System.out.println("关闭电视机......");        }public void changeChannel(){System.out.println("切换电视频道......");}
}

遥控器类:Controller.java

public class Controller {private Command openTVCommand;private Command closeTVCommand;private Command changeChannelCommand;public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){this.openTVCommand = openTvCommand;this.closeTVCommand = closeTvCommand;this.changeChannelCommand = changeChannelCommand;}/*** 打开电视剧*/public void open(){openTVCommand.execute();}/*** 关闭电视机*/public void close(){closeTVCommand.execute();}/*** 换频道*/public void change(){changeChannelCommand.execute();}
}

遥控器的三个按钮:

public class OpenTvCommand implements Command{private Television tv;public OpenTvCommand(Television tv){this.tv = tv;}public void execute() {tv.open();}
}
public class ChangeChannelCommand implements Command{private Television tv;public ChangeChannelCommand(Television tv){this.tv = tv;}public void execute() {tv.changeChannel();}
}
public class CloseTvCommand implements Command{private Television tv;public CloseTvCommand(Television tv){this.tv = tv;}public void execute() {tv.close();}
}

客户端:Client.java

public class Client {public static void main(String a[]){Television tv = new Television();Command openCommand,closeCommand,changeCommand;openCommand = new OpenTvCommand(tv);closeCommand = new CloseTvCommand(tv);changeCommand = new ChangeChannelCommand(tv);Controller control = new Controller(openCommand,closeCommand,changeCommand);control.open();           //打开电视机control.change();         //换频道control.close();          //关闭电视机}
}

运行结果:

打开电视机......
切换电视机频道......
关闭电视机......

命令模式扩展:前面说过,命令模式支持撤销命令:在电视遥控器中,我们还有这样一个按钮,那就是返回。用于切换到上面一个频道中去。在命令模式中也支持撤销操作,在这里我们只需要记录上一个频道,然后将上一个频道传入即可。在这里将 Command 进行一个简单的修改:将 execute() 改为 execute(int i);  i表示频道,用于进行频道切换。

/*** Command命令接口,为所有的命令声明一个接口。所有的命令都应该实现它*/
public interface Command {/*** 为了方便切换频道,这里使用参数i将频道传递* @param i*/public void execute(int i);
}

然后在Controller中添加channelUndo()方法,用于进行频道返回。并且需要进行一些简单的修改。

public class Controller {private Command openTVCommand;private Command closeTVCommand;private Command changeChannelCommand;public int nowChannel = 0;       //当前频道public int priorChannel;     //前一个频道,用于执行返回操作public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){this.openTVCommand = openTvCommand;this.closeTVCommand = closeTvCommand;this.changeChannelCommand = changeChannelCommand;}/*** 打开电视剧*/public void open(){openTVCommand.execute(0);}/*** 关闭电视机*/public void close(){closeTVCommand.execute(0);}/*** 换频道:只在当前频道递增*/public void change(){priorChannel = nowChannel;            //换频道前记录当前频道nowChannel++;       //频道+1changeChannelCommand.execute(nowChannel);}/*** 频道返回*/public void ChannelUndo(){changeChannelCommand.execute(priorChannel);          //将以前的频道传入//当前频道与前一个频道进行互换int tempChannel;tempChannel = priorChannel;priorChannel = nowChannel;nowChannel = tempChannel;}
}

客户端:

public class Client {public static void main(String a[]){Television tv = new Television();Command openCommand,closeCommand,changeCommand;openCommand = new OpenTvCommand(tv);closeCommand = new CloseTvCommand(tv);changeCommand = new ChangeChannelCommand(tv);Controller control = new Controller(openCommand,closeCommand,changeCommand);control.open();           //打开电视机control.change();         //换频道control.change();control.ChannelUndo();control.ChannelUndo();control.ChannelUndo();control.close();          //关闭电视机}
}

运行结果:


设计模式系列文章:

Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

Java设计模式之创建型:建造者模式

Java设计模式之创建型:单例模式

Java设计模式之创建型:原型模式

Java设计模式之结构型:适配器模式

Java设计模式之结构型:装饰器模式

Java设计模式之结构型:代理模式

Java设计模式之结构型:桥接模式

Java设计模式之结构型:外观模式

Java设计模式之结构型:组合模式

Java设计模式之结构型:享元模式

Java设计模式之行为型:策略模式

Java设计模式之行为型:模板方法模式

Java设计模式之行为型:责任链模式

Java设计模式之行为型:观察者模式

Java设计模式之行为型:访问者模式

Java设计模式之行为型:中介者模式

Java设计模式之行为型:命令模式

Java设计模式之行为型:状态模式

Java设计模式之行为型:备忘录模式

Java设计模式之行为型:迭代器模式

Java设计模式之行为型:解释器模式


参考文章:设计模式读书笔记-----命令模式_chenssy 的技术博客-CSDN博客

Java设计模式之行为型:命令模式相关推荐

  1. JAVA设计模式(14) —行为型模板方法模式(Template Method)

    1 定义: 模板方法模式(Template Method) Define the skeleton of an algorithm in anoperation, deferring some ste ...

  2. Java设计模式之创建型-建造者模式 (Builder)

  3. Java设计模式(16)中介模式(Mediator模式)

    Mediator定义:用一个中介对象来封装一系列关于对象交互行为. 为何使用Mediator模式/中介模式 各个对象之间的交互操作非常多,每个对象的行为操作都依赖彼此对方,修改一个对象的行为,同时会涉 ...

  4. Java设计模式(1)工厂模式(Factory模式)

    工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因 ...

  5. Java设计模式(8)组合模式(Composite模式)

    Composite定义:将对象以树形结构组织起来,以达成"部分-整体" 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. Composite比较容易理解,想到Compo ...

  6. Java设计模式(10)代理模式(Proxy模式)

    理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,P ...

  7. Java设计模式之行为型:解释器模式

    一.什么是解释器模式:         解释器模式,就是定义语言的文法,并建立一个解释器来解释该语言中的句子,通过构建解释器,解决某一频繁发生的特定类型问题实例. 这里我们将语言理解成使用规定格式和语 ...

  8. Java设计模式之行为型:访问者模式

    背景: 去医院看病时,医生会给你一个处方单要你去拿药,拿药我们可以分为两步走: (1)去柜台交钱,划价人员会根据处方单上的药进行划价,交钱. (2)去药房拿药,药房工作者同样根据处方单给你相对应的药. ...

  9. Java设计模式之行为型:状态模式

    背景: 介绍状态模式前,我们先看这样一个实例:公司力排万难终于获得某个酒店的系统开发项目,并且最终落到了你的头上.下图是他们系统的主要工作: 当第一眼看到这个系统时你就看出这是一个状态图,每个框都代表 ...

最新文章

  1. 人工智能推动全球业务的数据中心管理
  2. python拼音怎么写-Python 返回汉字的汉语拼音
  3. extract-text-webpack-plugin 的使用及安装
  4. 江南百景图自动刷水井,附带拼图教程
  5. 常用的函数式接口_Supplier接口
  6. 关于 Group 的另一个函数
  7. 安装mlxtend_python机器学习包mlxtend的安装和配置详解
  8. java socket android_Android:这是一份很详细的Socket使用攻略
  9. k8s使用volume将ConfigMap作为文件或目录直接挂载_Kubernetes in Action 06. 卷:将磁盘挂载到容器...
  10. password textbox setup
  11. 博微写狗.exe和博微电力工程造价深思4写狗
  12. C-V2X行业现状、产业化部署与演进路线
  13. ip ,子网掩码, 网关 ,主机位数,网络位数,子网数
  14. centos6.5重置密码
  15. Cross Domain Person Re-Identification With Large Scale Attribute Annotated Datasets参考文献解读
  16. 晶圆激光切割工艺流程
  17. 2017北京ICPC -G - Liaoning Ship’s Voyage (HihoCoder - 1633)几何
  18. 系统架构师论文-论软件设计模式的应用
  19. vscode中编写代码时tab键不能用
  20. 表格 table使用(属性)

热门文章

  1. 化工设备与反应器 第三章 直梁的弯曲
  2. 十八、深入Python函数
  3. pyqt5 中QSS
  4. 《失控玩家》爆火背后:什么才是拥抱人工智能的正确姿势?
  5. 博士申请 | ​英属哥伦比亚大学李霄霄助理教授招收全奖博士生、硕士生
  6. 预训练语言模型论文分类整理:综述、基准数据集、PLM的设计和分析
  7. 浅谈 CTR 预估模型发展史
  8. JVM【带着问题去学习 02】数据结构栈+本地方法栈+虚拟机栈+JVM栈运行原理
  9. 18款帝豪gl车机升级_好看又实用的2018款帝豪GL分享,感受它的魅力
  10. 《跟我学java》_《跟我学Java——基础篇02》