点菜系统中的命令模式

  • 现实生活中的命令模式
  • 命令模式
  • 代码实现
    • 抽象命令
    • 接收者
      • 京菜大厨
      • 川菜大厨
      • 粤菜大厨
    • 具体命令
      • 白切鸡
      • 白灼虾
      • 爆肚
      • 麻婆豆腐
      • 水煮鱼
      • 炸灌肠
    • 调用者
    • CommandMain
    • 运行结果
  • 总结

现实生活中的命令模式

首先我们来回顾一下去饭店吃饭是如何点菜的:

  1. 服务员来给我们看下菜单
  2. 我们告诉服务员我要什么菜
  3. 服务员告诉厨师要做什么菜
  4. 上菜

在整个流程中,实际做菜的厨师并没有与我们进行交互,取而代之的是服务员。服务员与我们沟通后,将沟通的结果告诉厨师,厨师做菜,服务员上菜。这样做有什么好处呢?好处是专人专责。厨师只负责做菜做菜做菜,其他的工作由服务员来做,这样就提高了厨师的工作效率,使厨师可以专注于做菜这一件事儿。

命令模式

命令模式是一种行为设计模式,它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。

在命令模式中,有四个主要角色:

  1. 抽象命令类:定义命令的接口
  2. 具体命令类:采用类似适配器模式的方式将接收者的具体方法封装成命令的实现类
  3. 实现着/接收者:命令真正的执行者
  4. 调用者/请求者:请求的发送者

代码实现

抽象命令

这个菜单项接口就是我们说的抽象命令,这个抽象命令有两个部分,一个是执行命令,一个是返回自己命令的内容

public interface OrderItem {/*** 执行*/void execute();String common();
}

由于demo是基于spring的,所以在OrderItem的基础上又包了一个AbstractOrderItem出来,这样OrderItem.common()可以默认返回beanName。

public abstract class AbstractOrderItem implements OrderItem, BeanNameAware {private String beanName;@Overridepublic String common() {return beanName;}@Overridepublic void setBeanName(String name) {this.beanName = name;}
}

接收者

在这个点菜系统中,命令的接收者是后厨的大厨

京菜大厨

@Component
public class BeijingCuisineChef {private static final Logger logger = LoggerFactory.getLogger("京菜厨师");public void cookZhaGuanChang(){logger.info("炸灌肠做好了");}public void cookBaoDu(){logger.info("爆肚做好了");}
}

川菜大厨

@Component
public class SichuanCuisineChef {private static final Logger logger = LoggerFactory.getLogger("川菜厨师");public void cookShuiZhuYu(){logger.info("水煮鱼做好了");}public void cookMaPoDouFu(){logger.info("麻婆豆腐做好了");}
}

粤菜大厨

@Component
public class CantoneseChef {private static final Logger logger = LoggerFactory.getLogger("粤菜厨师");public void cookBaiQieJi(){logger.info("白切鸡做好了");}public void cookBaiZhuoXia(){logger.info("白灼虾做好了");}
}

具体命令

具体命令的职责是实现抽象命令的同时调用接收者的具体方法。这一步感觉和适配器模式超级像。

白切鸡

@Component("baiqieji")
public class BaiQieJiOrderItemImpl extends AbstractOrderItem {@Autowiredprivate CantoneseChef cantoneseChef;@Overridepublic void execute() {cantoneseChef.cookBaiQieJi();}
}

白灼虾

@Component("baizhuoxia")
public class BaiZhuoXiaOrderItemImpl extends AbstractOrderItem {@Autowiredprivate CantoneseChef cantoneseChef;@Overridepublic void execute() {cantoneseChef.cookBaiZhuoXia();}
}

爆肚

@Component("baodu")
public class BaoDuOrderItemImpl extends AbstractOrderItem{@Autowiredprivate BeijingCuisineChef beijingCuisineChef;@Overridepublic void execute() {beijingCuisineChef.cookBaoDu();}
}

麻婆豆腐

@Component("mapodoufu")
public class MaPoDouFuOrderItemImpl extends AbstractOrderItem {@Autowiredprivate SichuanCuisineChef sichuanCuisineChef;@Overridepublic void execute() {sichuanCuisineChef.cookMaPoDouFu();}
}

水煮鱼

@Component("shuizhuyu")
public class ShuiZhuYuOrderItemImpl extends AbstractOrderItem {@Autowiredprivate SichuanCuisineChef sichuanCuisineChef;@Overridepublic void execute() {sichuanCuisineChef.cookShuiZhuYu();}
}

炸灌肠

@Component("zhaguanchang")
public class ZhaGuanChangOrderItemImpl extends AbstractOrderItem{@Autowiredprivate BeijingCuisineChef beijingCuisineChef;@Overridepublic void execute() {beijingCuisineChef.cookZhaGuanChang();}
}

调用者

调用者自然就是服务员了

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Waiter implements ApplicationContextAware {private static final Logger logger = LoggerFactory.getLogger("服务员");private List<String> orderItems;private ApplicationContext applicationContext;public void showOrder(){String[] beanNamesForType = applicationContext.getBeanNamesForType(OrderItem.class);logger.info("菜单:{}", (Object) beanNamesForType);}public void beginOrder(){this.orderItems = new ArrayList<>();}public void addItem(String item){this.orderItems.add(item);}public void endOrder(){for (String orderItem : orderItems) {OrderItem orderItemBean = applicationContext.getBean(orderItem, OrderItem.class);orderItemBean.execute();}}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

CommandMain

@Configuration
@ComponentScan("com.example.designpatterns.command")
public class CommandMain {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CommandMain.class);Waiter waiter = context.getBean(Waiter.class);waiter.showOrder();waiter.beginOrder();waiter.addItem("baodu");waiter.addItem("mapodoufu");waiter.addItem("baiqieji");waiter.endOrder();}
}

运行结果

从结果上,程序运行正常

总结

  1. 命令模式使程序变得更加复杂了。本来一个Waiter+3个Chef四个类就能搞定,结果现在搞出来了N多个类。
  2. 程序的扩展更加容易了,同时扩展后带来的影响变得可以估量。
  3. 我们平时开发中最常见的命令模式应该是Statement了。一条SQL跟一个命令没啥区别。
  4. 命令模式很好的实践了单一职责原则开闭原则
  5. 如果有必要的话,我们可以将一系列命令组合成一个更加强大的命令。

点菜系统中的命令模式相关推荐

  1. 命令模式 java_JAVA中的命令模式实例教程

    原文链接  作者:Pankaj Kumar 译者:f0tlo <1357654289@qq.com> 命令模式是一种行为模式,因此,它处理的是对象的行为.命令模式为系统中不同的对象提供中性 ...

  2. Activiti 中的 命令模式与责任链模式

    Activiti 中的 命令模式与责任链模式 类图: 标准命令模式: 意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化. 主要解决:在软件系统中,行为请求者与行为实现者通常是一 ...

  3. JAVA中的命令模式实例教程

    原文链接  作者:Pankaj Kumar 译者:f0tlo <1357654289@qq.com> 命令模式是一种行为模式,因此,它处理的是对象的行为.命令模式为系统中不同的对象提供中性 ...

  4. linux系统中scp命令的用法

    scp是 secure copy的缩写, scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令.linux的scp命令可以在linux服务器之间复制文件和目录. scp命令的用处: scp ...

  5. linux系统中ssh命令,Linux系统中SSH 命令的用法有哪些?

    今天小编要跟大家分享的文章是关于Linux系统中SSH命令的用法有哪些?一个系统管理员可能会同时管理着多台服务器,这些服务器也许会放在不同的地方.要亲自一台一台的去访问来管理它们显然不是最好的方法,通 ...

  6. 【游戏设计模式】之二 论撤消重做 回放系统的实现 命令模式

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴!  本系列 ...

  7. linux scp涉及到权限,linux系统中scp命令的用法(Permission denied排错二例)

    linux系统中scp命令的用法 注意: 在使用过程中如果出现   -bash: scp: command not found 请执行yum install openssh-clients scp是 ...

  8. linux cp -r 参数,Linux系统中cp命令的参数及用法详解

    Linux系统中cp命令主要是用来复制文件或者目录.下面由学习啦小编为大家整理了Linux系统中cp命令的参数及用法详解的相关知识,希望对大家有帮助! Linux系统中cp命令的参数及用法详解:参数说 ...

  9. linux命令 scp怎么用,linux系统中scp命令怎么使用

    scp是有Security的文件copy,Linux为我们提供了两个用于文件copy的命令,一个是cp,一个是scp,但是他们略有不同,cp 主要是用于在同一台电脑上,在不同的目录之间来回copy文件 ...

最新文章

  1. 会不会导致内存泄漏_可能会导致.NET内存泄露的8种行为
  2. su的时候密码认证失败的解决方法
  3. Java基础学习总结(117)——Feign入门使用详解
  4. HUD 2544 最短路 迪杰斯特拉算法
  5. leetcode28 Implement strStr() 在字符串中寻找目标字符串
  6. 程序如何在两个gpu卡上并行运行_【他山之石】如何支撑上亿类别的人脸训练?显存均衡的模型并行(PyTorch实现)...
  7. .NET Core 新手上路
  8. 5g手机可以用4g的手机卡吗
  9. 解决VMware虚拟机宿主机与虚拟机通讯慢
  10. 什么是数据安全,为什么它很重要?
  11. java软件测试基础
  12. 小程序接入h5页面_小程序与H5如何互相跳转
  13. 再贴一个Fleaphp相关的
  14. 7-1 评委打分 (5分)
  15. 面试复试重点 算法与数据结构
  16. 嵌入式应用市场四大热点及趋势
  17. springboot+mysql+基于Spring boot开发电子宿舍管理系统 毕业设计-附源码132056
  18. 华云数据:做数字经济时代的信创云计算专家
  19. 4Cs营销理论(转载)
  20. 关于冈萨雷斯的《数字图像处理》的坑与资源!

热门文章

  1. python创建数字列表_Python 生成一个从0到n个数字的列表4种方法小结
  2. 远程FPGA虚拟实验平台用SystemVerilog HDL实现硬布线控制器
  3. CentOS7下安装google chrome浏览器
  4. mysql密码错误解决方法--windows和ubuntu18.04
  5. 什么是 SSH 以及常见 ssh 用法
  6. 读书笔记:《量化投资实务》
  7. QT里的函数void Q_INIT_RESOURCE ( name )
  8. 主要有哪些具体的技术指标?
  9. ADC类型和技术指标
  10. 还不了解什么是商业智能(BI)?看完这篇文章就懂了