命令模式描述

官方解释
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

个人理解
将软件代码划分为三个方面:① 调用者(入口)、② 命令、③ 执行者。

整体流程为 调用者与客户做直接交互,将客户的要求转成相应的命令并且要求命令触发执行者的相关操作,可以理解为是一种自顶向下的分析方法。

类结构与基础实现

  • Invoker
    调用者, 负责持有命令对象并触发命令执行,命令模式的交互入口 ;
  • Client
    实际与命令模式交互的甲方爸爸,负责提需求,也就是产生命令及命令的执行者 如甲方爸爸要求某程序员做出能随心情变色的壁纸,那甲方爸爸是Client,做出能 随心情变色的壁纸是Command,某程序员是receiver;
  • Command
    定义统一的命令格式(接口 or 抽象类),每个命令会有对应的接收者;
  • receiver
    接收者,也是每条命令的实际处理者;

总结为一句话:由谁发出怎样的命令,命令的接收方是谁;

基础实现

/*** 命令接口 */
public interface Command {void execute();void undo();
}
/*** 命令实现*/
public class ConcreteCommand implements Command {private Receiver receiver;public void execute() {receiver.doSomeThing();System.out.println("------------ concrete execute -------------");}public void undo() {System.out.println("------------ concrete undo -------------");}
}
/*** 接收方接口,看情况去判断是否需要再抽象* 如果为了每个处理类功能更加单一,则可以考虑再加一层* 这样不会导致啥都往一个地方怼,后期改动也麻烦*/
public interface Receiver {void doSomeThing();
}
/*** 接收方实现类 */
public class ConcreteReceiver implements Receiver {public void doSomeThing() {System.out.println("--------- receiver do something ----------");}
}
/*** 调用方*/
public class Invoker {private Command command;public void call () {command.execute();}public void cancel () {command.undo();}
}

使用流程

命令、接收者 、调用者 并没有与生俱来的关系,所以需要有一步装配的过程 ;
调用顺序

智能、半智能、宏命令

普通的命令模式是需要依赖接收者去执行请求的。
对于不需要调用接收者靠自身就可以完成命令的情况就称之为智能命令
对于依旧需要依赖接收者,但自身可以完成大半功能的命令则称之为半智能命令
对于多个命令的结合体形成的命令称之为宏命令,即命令里保持了一系列命令的集合(一份菜单,多个菜品制作命令)。

可撤销命令

反操作式
如加减,那加的操作就对应一份减的操作,当撤销时还原减操作的日志;会与 备忘录模式有关联;

存储恢复式
在操作前,保留一份现场存储,当撤销时,将存储还原成保存的这一份;

生活案例

1、烧烤店点菜案例
假设在烧烤店点菜没有服务员这个中间介质,顾客都直接跟厨师点单

厨师的任务就会有记单(日志)、改单、记账、收账、制菜、上菜等;每个新厨师再加入工作前除了熟悉自己的环境还要额外了解其他业务(冗余,成本高,不好扩展);

如此紧凑繁琐(紧耦合)的工作很容易导致任务错乱,效率低下,影响菜品等;还会出现顾客改单,厨师太忙没有及时跟进而导致出错等情况;

引入服务员这个调用者后
厨师只需要与订单交互,做好菜品即可;与顾客打交道的事情交给服务员;
这样整体的结构变得更加清晰,容易扩展和维护,主要体现在:

  1. 饭店此时想增加小龙虾的菜品 ,那只需要增加制作小龙虾的师傅和菜单即可;
  2. 烧烤店想扩大规模,增加服务员和厨师即可;
  3. 改单、下单等问题由服务员更近后反馈给厨师即可;
  4. 所有人都有自己的专一目标,效率 和质量都提升了;
  5. 客户只需要向服务员沟通即可,无需关注菜怎么做的;

这里的参考代码实现如下:

public abstract class Command {// 命令需要对应到相应执行者protected BarbecueMaster barbecueMaster;public Command(BarbecueMaster barbecueMaster) {this.barbecueMaster = barbecueMaster;}/*** 命令执行*/public abstract void execute();/*** 取消命令*/public abstract void undo();
}// ----------------------------------------------------
// 烤牛肉命令
public class BeefCommand extends Command {public BeefCommand(BarbecueMaster barbecueMaster) {super(barbecueMaster);}public void execute() {try {System.out.println(barbecueMaster.roastedBeef());} catch (InterruptedException e) {System.out.println("【BeefCommand】命令被中断");} finally {Thread.currentThread().interrupt();}}@Overridepublic void undo() {System.out.println("【BeefCommand】命令被取消");}
}// -----------------------------------------------------------
// 烤鸡翅命令
public class ChickenWingCommand extends Command  {public ChickenWingCommand(BarbecueMaster barbecueMaster) {super(barbecueMaster);}public void execute() {try {System.out.println(barbecueMaster.roastedChickenWind());} catch (InterruptedException e) {System.out.println("【ChickenWingCommand】命令被中断");} finally {Thread.currentThread().interrupt();}}@Overridepublic void undo() {System.out.println("【ChickenWingCommand】命令被取消");}
}
// -------------------------------------------------------
// 烧烤厨师
public class BarbecueMaster {public String roastedChickenWind () throws InterruptedException {TimeUnit.SECONDS.sleep(2);return "【BarbecueMaster】: 制作烤鸡翅";}public String roastedBeef () throws InterruptedException {TimeUnit.SECONDS.sleep(2);return "【BarbecueMaster】: 制作烤牛肉";}
}
// --------------------------------------------------------
// 服务员
public class Waiter {private List<Command> commands;public Waiter(List<Command> commands) {this.commands = commands;}public Waiter() {commands = new ArrayList<>();}public void addCommand (Command command) {commands.add(command);}public void cancel(Command command) {// 需要处理成已处理的话不能执行撤销commands.remove(command);command.undo();}public void notifyBarbecueMaster() {System.out.println("【Waiter】将订单提交, 开始有序执行命令");commands.forEach(Command::execute);}
}
//------------------------------------------------
// 客户端
public class Client {public static void main(String[] args) {// 创建invokerWaiter waiter = new Waiter();// 组装命令 start// 创建receiverBarbecueMaster barbecueMaster = new BarbecueMaster();// 生成命令, 需要依赖命令接收方BeefCommand beefCommand = new BeefCommand(barbecueMaster);ChickenWingCommand chickenWingCommand =new ChickenWingCommand(barbecueMaster);// 组装命令 end// 发送命令waiter.addCommand(beefCommand);waiter.addCommand(chickenWingCommand);waiter.notifyBarbecueMaster();// 取消鸡翅waiter.cancel(chickenWingCommand);}
}

2、电脑开机案例
启动一台机器时,我们往往只需要按一下电源键即可,至于其他的软硬件初始化的事情就直接交给主板去做;关机的时候,也仅仅只需要按动关机键即可;

这个案例其实也是有命令模式的身影,如主机壳其实就相当于Invoker,电源键等按钮发出的信号指令就相当于command,而主板就是实际的receiver;


生活中还有很多这样的事例可以用于描述这个模式,
如程序员、项目经理、客户三者的关系 ,投资方、公司、员工三者的关系、计算器等;

优点

  • 松散耦合,请求方和接收方完全隔离,双方无需互相知道谁是谁,谁做了什么 。
  • 扩展高效,增加新命令时无需影响旧命令,只需要增加新的即可。
  • 动态控制请求的队列化、日志化、参数化等。

缺点是设计模式的通病,引入模式势必就带来了 结构上的复杂性,类膨胀问题;

使用场景

  • 需要支持undo操作;
  • 需要将请求和执行动作进行抽象;
  • 需要在不同时刻对请求进行排列执行;
  • 在系统崩溃后恢复时需要将功能重新执行一遍;
  • 需要事务时可用该模式对事务进行建模 。

参考:《大话设计模式》、《设计模式之禅》、《研磨设计模式》。

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

  1. 行为型设计模式(八)命令模式【王者荣耀的服务端实现】

    目录 一.概念及原理 二.具体实例 2.1 游戏开发背景知识 2.2 线程内轮询接收请求和处理请求实现 三.命令模式 VS 策略模式 四.小结 五.参考链接 一.概念及原理 命令模式的英文翻译是 Co ...

  2. 设计模式 之 命令模式

    2019独角兽企业重金招聘Python工程师标准>>> 设计模式 之 命令模式 命令模式比较简单,不过多赘述 为什么需要命令模式 将"行为请求者"与"行 ...

  3. 【设计模式】命令模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.命令模式简介 二.命令模式 适用场景 三.命令模式 优缺点 四.命令模式 与 备忘录模式 五.命令模式 代码示例 1.命令接口 2.发布命令类 3.关闭命令类 4.游戏类 5.命令执行者 ...

  4. 乐在其中设计模式(C#) - 命令模式(Command Pattern)

    原文:乐在其中设计模式(C#) - 命令模式(Command Pattern) [索引页] [源码下载] 乐在其中设计模式(C#) - 命令模式(Command Pattern) 作者:webabcd ...

  5. 实验一:行为型设计模式之Strategy模式

    实验一:行为型设计模式之Strategy模式 https://blog.csdn.net/weixin_43206161 一.实验目的 熟练使用JAVA实现行为型设计模式-策略模式,理解设计模式的模式 ...

  6. 23种设计模式之命令模式和策略模式的区别

    文章目录 概述 命令模式 策略模式 相同点 总结 概述 命令模式和策略模式确实很相似,只是命令模式多了一个接收者(Receiver)角色.它们虽然同为行为类模式,但是两者的区别还是很明显的.策略模式的 ...

  7. 设计模式之命令模式(行为型)

    目录 一.模式定义 二.模式角色 三.模式分析 四.典型例子 五.适用场景 一.模式定义 命令模式(Command Pattern):将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分离,两 ...

  8. 设计模式之命令模式(Command)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  9. Android设计模式之——命令模式

    一.介绍 命令模式(Command Pattern),是行为型设计模式之一.命令模式相对于其他的设计模式来说并没有那么多的条条框框,其实它不是一个很"规范"的模式,不过,就是基于这 ...

最新文章

  1. Spring官网改版后下载方式
  2. SpringAOP静态代理和动态代理
  3. Linux ifconfig指令
  4. netbeans7.4_使用NetBeans 7.4 beta提示进行更好的基于JUnit的单元测试
  5. VB-VB.NET中 从字符串“XX”到类型“Double”的转换无效
  6. 【IDEA】IDEA中使用git将项目上传到码云上
  7. python来构建多层网络
  8. autofac文档:事件
  9. Servlet乱码解决
  10. win10+eclipse+hadoop2.6.0 开发环境
  11. 梦幻西游69人最多的服务器,梦幻西游:老王探访难以形容的鬼区,没有摆摊摊位,找不到69玩家...
  12. spring与spring mvc
  13. 你最关心的马蜂窝事件舆论全景图在这里,用文本挖掘一挖到底
  14. 【Unity】文字游戏制作插件Fungus教程(1)基础的使用方法
  15. PT002(JspStudy)安装与端口解决问题
  16. 电源管理方案APM和ACPI比较
  17. 405服务器响应失败,服务器返回HTTP响应代码:405
  18. linux c 获取文件大小
  19. 你所不知道的测试经验分享之安卓UI控件定位!
  20. js base64解码JWT失败:VM273:1 Uncaught DOMException: Failed to execute 'atob' on 'Window': The string to

热门文章

  1. 另类远控:木马借道商业级远控软件的隐藏运行实现
  2. bat命令清理Window应用注册表(Unity开发Window应用)
  3. js实现网页打印分页打印
  4. 201508-04 开讲啦 张信哲:我不愿做唱歌的机器
  5. vue按需加载组件-webpack require.ensure(转)
  6. java毕业设计宠物用品商城服务系统Mybatis+系统+数据库+调试部署
  7. 背景图铺满屏幕的方法
  8. 虚拟机配置NAT网络
  9. JVAV入门之JDK12安装及搭建
  10. 【微信小程序】客服系统,客服聊天发送商品详情,快捷发送链接和图文消息,附代码和流程