目录

一、概念

二、命令模式案例分析

三、总结


一、概念

命令模式是一个高内聚的模式,其定义为:将请求以命令的形式封装成一个对象,传给调用对象,然后调用对象去找能处理该命令的接收者,然后由命令接收者真正去执行命令。命令模式属于行为型模式。

  • 命令模式的通用UML类图如下所示:

角色分析:

  • Command: 抽象命令对象,声明了需要执行的所有命令,可以是接口或者抽象类,一般来说要对外公布一个execute()方法用来执行命令;
  • Invoker: 请求的调用者角色,接收到命令,并执行命令;
  • Receiver: 请求接收者,真正执行操作的对象( 接收命令并且执行命令 );
  • ConcreateCommand: 聚合了请求接收者引用,将接收者与命令进行绑定,调用接收者相应的方法实现execute();
  • Client类:客户端调用;

二、命令模式案例分析

下面通过发出唱歌、跳舞等命令,实现唱歌、跳舞功能的示例说明命令模式的使用:

类图如下所示:

命令模式的编写步骤可以参考如下:

  • 第一步:声明一个命令接口 (Command);
  • 第二步:构建那些可以具体完成命令的角色(Receiver);
  • 第三步:构建各种具体命令(ConcreteCommand);
  • 第四步:构建命令的调用者 (Invoker);
  • 第五步:客户端使用;

首先,我们需要定义一个抽象命令对象,其中包含一个execute执行命令的方法:

/*** 第一步:声明一个命令接口 (Command)* 命令接口,所有具体的命令都会实现此接口,Invoker只认识此接口* <p>* 抽象命令类:抽象的命令,可以根据不同类型的命令写出不同的实现.*/
public interface Command {/*** 调用命令*/void execute();/*** 命令Key* @return*/String commandKey();
}

有了命令对象,从上面的类图中我们可以看到,Receiver命令接收者才是真正执行命令的对象,下面我们创建两个Receiver命令接收者,分别执行唱歌、跳舞动作,代码如下:

/*** @Description: 第二步:创建接收者:真正执行命令的对象*/
public class SingReceiver {public void sing() {System.out.println("唱歌...");}}public class DanceReceiver {public void dance() {System.out.println("跳舞...");}}

命令接收者有了,接下来就需要增加对应的唱歌、跳舞命令,聚合前面我们定义的Receiver请求接收者,由它们来完成具体的动作:

/*** @Description: 具体命令类: 唱歌命令*/
public class SingCommand implements Command {/*** 持有真正执行命令对象的引用*/private SingReceiver singReceiver;public SingCommand(SingReceiver singReceiver) {this.singReceiver = singReceiver;}@Overridepublic void execute() {singReceiver.sing();}@Overridepublic String commandKey() {return "唱歌命令";}
}/*** @Description: 具体命令类: 跳舞命令*/
public class DanceCommand implements Command {private DanceReceiver danceReceiver;public DanceCommand(DanceReceiver danceReceiver) {this.danceReceiver = danceReceiver;}@Overridepublic void execute() {danceReceiver.dance();}@Overridepublic String commandKey() {return "跳舞命令";}
}

接下来,就需要一个命令的调用者Invoker,来发起调用的命令,代码如下:

/*** @Description: 第四步:构建命令的调用者 (Invoker)*/
public class Invoker {/*** 命令集合*/private final List<Command> commandList = new ArrayList<>();public void clearCommand() {commandList.clear();}/*** 设置一套命令,不知道具体执行者是谁** @param command*/public void addCommands(Command command) {System.out.println("调度器收到: " + command.commandKey() + ",即将开始执行..");commandList.add(command);}/*** 执行命令*/public void executeCommand() {for (Command command : commandList) {System.out.println("调度器执行: " + command.commandKey());command.execute();}}}

下面我们定义一个场景类,看下如何利用Invoker调用对应的命令:

/*** 命令模式使用场景:* 1.当需要将各种执行的动作抽象出来,使用时通过不同的参数来决定执行哪个对象* 2.当某个或者某些操作需要支持撤销的场景* 3.当要对操作过程记录日志,以便后期通过日志将操作过程重新做一遍时* 4.当某个操作需要支持事务操作的时候* <p>* 使用步骤:* 第一步:声明一个命令接口 (Command)* 第二步:构建那些可以具体完成命令的角色(Receiver)* 第三步:构建各种具体命令(ConcreteCommand)* 第四步:构建命令的调用者 (Invoker)* 第五步:客户端使用*/
public class Client {public static void main(String[] args) {//通过请求者(invoker)调用命令对象(command),命令对象中调用了命令具体执行者(Receiver)Invoker invoker = new Invoker();SingReceiver singReceiver = new SingReceiver();SingCommand singCommand = new SingCommand(singReceiver);invoker.addCommands(singCommand);//执行唱歌命令invoker.executeCommand();System.out.println("====================");invoker.clearCommand();DanceReceiver danceReceiver = new DanceReceiver();DanceCommand danceCommand = new DanceCommand(danceReceiver);invoker.addCommands(danceCommand);//执行跳舞命令invoker.executeCommand();}}

执行结果如下:

调度器收到: 唱歌命令,即将开始执行..
调度器执行: 唱歌命令
唱歌...
====================
调度器收到: 跳舞命令,即将开始执行..
调度器执行: 跳舞命令
跳舞...

我们可以看到,通过请求者(invoker)调用命令对象(command),命令对象中调用了命令具体执行者(Receiver),这就是命令模式。

三、总结

命令模式的优点:

  • 类间解耦

解耦了请求调用者和请求接收者,互不影响互不关心,只需要发出一个命令即可完成操作,不需要了解到底是哪个接收者执行;

  • 可扩展性

Command的子类非常容易进行扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合;

  • 命令模式结合其他模式更优秀

命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command子类的膨胀问题;

命令模式的缺点:

  • 如果命令很多,开发起来会比较困难;
  • 如果使用命令模式,即使很简单的逻辑也要封装成一个命令对象,有可能会产生很多的具体命令对象,增加系统的复杂度;

命令模式的使用场景:

  • 如果系统中有实现记录日志、撤销操作等功能,可以考虑使用命令模式。但是由于命令模式引入了请求调用者和请求接收者两个角色对象,在详细设计时需要充分考虑是否真正值得使用命令模式。

设计模式 (十六) 命令模式相关推荐

  1. Head First 设计模式总结(六) 命令模式

    本文总结了<Head First 设计模式>中的命令模式 命令模式--将请求封装成"对象",以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持撤销操作. ...

  2. php 命令设计模式示例,php设计模式(十九)命令模式-Fun言

    命令模式就和名字一样: 比较适合执行命令的场景: 命令发送者只管调用具体命令类中的 execute() 方法: 然后在具体命令类中设定命令接收者: 可以消除命令发送者和命令接受者之间的耦合: 并且可以 ...

  3. 【白话设计模式八】命令模式(Command)

    为什么80%的码农都做不了架构师?>>>    #0 系列目录# 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factory) [白话设计模式二] ...

  4. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  5. 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)

    设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的有用 ...

  6. Head First 设计模式中的命令模式 的一个错误

    最近在看Head First 设计模式,其中命令模式中有讲到实现撤销功能,并且作者还出了一道题, 下面的是书中习题: public class MarcoCommand implements Comm ...

  7. 设计模式笔记之十四 (命令模式)

    命令模式 命令模式是一种比较容易理解的设计模式,顾名思义,就是调用者发一个命令,有人给做完就行了,无关乎怎么做,也无关乎谁做. 我们继续我们以往的方式:理论联系实践的方式来理解命令模式. 最近我们实验 ...

  8. 设计模式 ( 十六 ) 观察者模式Observer(对象行为型)

    设计模式 ( 十五 ) 观察者模式Observer(对象行为型) 1.概述 一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力.当对象们连接在一起时,它们就可以相互提供服务和信息. 通常来 ...

  9. 【源码分析设计模式 13】命令模式

    一.基本介绍 1.在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作时哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计 ...

  10. 设计模式笔记:命令模式

    首先看看命令模式的定义:命令模式将请求封装成对象,以便使用不同的请求.队列或者日志来参数化其他对象.命令模式也支持撤销的操作. 所谓参数化,我的理解是实际执行的对象,比如light(电灯).strer ...

最新文章

  1. 关于数据库,你可能最想知道的几件事
  2. AI一分钟 | 美女机器人竟然想生孩子,太可怕了!比尔·盖茨当选中国工程院外籍院士
  3. cocoahttpserver 载入本地html,利用CocoaHttpServer搭建手机本地服务器
  4. mysql where后面if_mysql查询语句where后面加if判断
  5. WWDC 2018 New Localization Workflows
  6. createbitmap 旋转90度_小学数学,图形的运动,平移与旋转
  7. css --- [小结]让盒子水平垂直居中的解决方案
  8. django开发商城(提供初始数据,商城首页及购物车)
  9. mysqldump备份(全量+增量)
  10. django-项目的创建-应用注册-项目运行
  11. jQuery如何去判断页面是否有父页面?
  12. android studio创建第一个安卓程序加载html5页面(一)
  13. java适配器有哪些_Java中适配器模式(Adapter)是什么? 适配器模式(详解)
  14. golang 解决 TCP 粘包问题
  15. 利用 mount 指令解决 Read-only file system的问题
  16. 控制网平差(C++实现)
  17. Iterator中的 FailFast FailSafe【学习笔记】
  18. 打印机脱机了怎么恢复打印
  19. git把一个分支的commit merge到另外一个分支
  20. 清风数学建模学习之TOPSIS法

热门文章

  1. TensorFlow 强化学习快速入门 -- Kaushik Balakrishnan 读后感
  2. Xcode在 release 模式下断点调试
  3. 线性可分支持向量机与硬间隔最大化
  4. 2020 华为 一面 二面 面经
  5. html字段集,禁用HTML DOM字段集的属性
  6. )类 新建javafx程序时_JavaFX 类 RadioButton用法及代码示例
  7. 【ECG实践篇(1)】MIT-BIH数据库数据解析的方法以及使用rdann获取人工标注注释的方法
  8. 计算机网络超详细笔记(一):计网概述
  9. 【2018-2019 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) F】Rectangles【扫描线】
  10. 360 绑架浏览器首页的解决方法