zoukankan      html  css  js  c++  java
  • 设计模式——命令模式

    命令模式定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

        首先我们的集中点在“命令”两个字身上。命令的汉语解释为:命令(令)是国家行政机关及其领导人发布的指挥性和强制性的公文。说白了命令的发生需要发令者执行者。而且发令者和执行者各司其职,发令者只负责发令,甚至他自己都可以不知道这条命令具体该如何执行,而执行者只负责执行这条命令,他不需要知道如何发令,很多时候他也没有资格去发令。
        以简单的"电脑开机"来举例说明:人扮演的是发令者的角色,而电脑上的开机组件扮演的是命令执行者角色。人不需要去知道开机这条命令在电脑内部具体如何执行,只需要知道按一下开机键即可,具体的开机操作由电脑开机组件去完成,这样就达到了发令者和执行者之间解耦的效果。人知道如何发令之后,可以通过"按一下按键"这一操作来执行很多操作,比如开启电视,开启车门,切换空调模式等等,人只需要知道"按一下键"来发号施令,而具体的操作由相应的命令接收者来完成。
        下面以"电脑开机"来详细说明什么是命令模式:
        命令模式中涉及到几个通用的类:Command, ConcreteCommand, Client, Invoker, Receiver。具体的名字可以由用户根据自己的习惯而定,如果联系到"电脑开机"这一实际操作,那么这几个类的映射关系如下:
    • Command  ----->  命令的通用接口
    • ConcreteCommand  ----->  开机命令
    • Client  ----->  用户
    • Invoker  ----->  开机键与开机组件之间的线路
    • Receiver  ----->  开机组件
        ConcreteCommand实现了通用命令接口Command,在这里为开机命令,其中封装了命令的接收者和触发命令执行的方法。Client(用户)希望开机,所以他需要发一个开机命令给开机组件,用户需要创建一个命令,而且还需要指定这个命令是开机命令。用户按键表示用户在创建一个命令,而用户按的是开机键,表示用户正在创建的是一个开机命令。当用户按下开机键之后Invoker(开机键与开机组件之间的线路)会将这个命令通知到开机组件,开机组件接收到命令之后,就开始干活啦,然后电脑就启动了。在这个过程中,用户是不需要知道电脑具体是怎么开机的,而只需要发号开机命令即可。
    下面我们来具体编程实现(UML图如下):
     

     1 先定义一个通用命令接口:
     2 /**
     3  * 命令接口
     4  * @author Apache_xiaochao
     5  *
     6  */
     7 public abstract class Command {
     8  
     9  protected Receiver receiver; //命令接收者
    10  
    11  /**
    12   * 设置命令的接收者
    13   * @param receiver
    14   */
    15  public Command(Receiver receiver) {
    16     super();
    17     this.receiver = receiver;
    18  }
    19 
    20  /**
    21   * 命令执行函数
    22   */
    23  public abstract void execute();
    24 }
     1 定义具体的开机命令(这里使用了通用类名,实际中可以替换成更加直观的类名):
     2 /**
     3  * 具体的命令
     4  * @author Apache_xiaochao
     5  *
     6  */
     7 public class ConcreteCommand extends Command {
     8  
     9  /**
    10   * 设置命令的接收者
    11   * @param receiver
    12   */
    13  public ConcreteCommand(Receiver receiver) {
    14     super(receiver);
    15     // TODO Auto-generated constructor stub
    16  }
    17 
    18  @Override
    19  public void execute() {
    20   //命令的主体 ,命令本身不去执行具体的操作,而是给命令的接收者一个通知,具体操作由命令的接收者去做
    21     receiver.doSomething();
    22  }
    23 
    24 }
     1 定义开机组件(这里使用了通用类名,实际中可以替换成更加直观的类名):
     2 /**
     3  * 这是一个命令接收者,负责执行命令
     4  * @author Apache_xiaochao
     5  *
     6  */
     7 public class Receiver {
     8  
     9  /**
    10   * 开机函数
    11   */
    12  public void doSomething(){
    13     System.out.println("命令接收者:Windows 正在启动...");
    14  }
    15 }
     1 定义用户类:
     2 /**
     3  * 客户类,创建一个命令,并设置命令的接收者
     4  * @author Apache_xiaochao
     5  *
     6  */
     7 public class Client {
     8  
     9  /**
    10   * 创建一个命令,并设置命令的接收者
    11   */
    12  public Command createCommand(){
    13     Receiver receiver = new Receiver();
    14     //创建一条命令,并指定命令的接收者
    15     Command command = new ConcreteCommand(receiver);
    16     return command;
    17  }
    18 }
     1 定义开机键与开机组件之间的线路(这里使用了通用类名,实际中可以替换成更加直观的类名):
     2 /**
     3  * 命令传递类
     4  * @author Apache_xiaochao
     5  *
     6  */
     7 public class Invoker {
     8  
     9  private Command command;
    10  
    11  /**
    12   * 通知命令接收者执行命令
    13   */
    14  public void notifyReceiver(){
    15     command.execute();
    16  }
    17  /**
    18   * 获取命令
    19   * @param command
    20   */
    21  public void setCommand(Command command) {
    22     this.command = command;
    23  }
    24 }
     1 public class Driver {
     2  public static void main(String[] args) {    
     3     //用户按下开机键  
     4     Client client = new Client();  
     5     Command command = client.createCommand();   //客户端创建一条命令
     6     //通信线路传递命令
     7     Invoker invoker = new Invoker();
     8     invoker.setCommand(command);     //获取用户创建的命令
     9     invoker.notifyReceiver();   //传递命令,通知开机组件,有人要开机
    10  }
    11 }
    整个程序的大致流程为:
    1. Client创建命令,并指定命令的接收者
    2. Invoker传递命令,通知命令接收者执行命令
    3. Receiver接收命令,解析并执行
        命令的详细信息封装在Command对象中,用户不必关心命令中具体是什么样子,只需要创建,并指定接收者即可,接收者自己会去解析并执行命令。
        这里的命令都是指单一的命令,当用户按下开机键的时候,当然也可以触发一系列操作,比如开机的同时弹出光驱等(只是举例,实际中这肯定是不可取的),称之为宏命令。
        当然我们还可以在命令模式中定义撤销的功能(比如误按了开机键,想取消开机),思路都是记录前一次或者几次的操作,然后执行相应的反操作来完成的。

    总结:
    1. 命令模式将发出命令的对象和执行命令对象之间解耦
    2. 发令者和执行者之间通过命令对象进行沟通,命令对象封装了命令接收者,以及一个或一组动作
    3. 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行之前的状态
    4. 宏命令是命令的一种简单延伸,允许调用多个命令,支持撤销
    5. 命令也可以用来实现日志和事务系统
  • 相关阅读:
    LINUX基础学习之基础命令(3)--2019-11-22
    LINUX基础学习之基础命令(2)--2019-11-18
    Linux基础学习之基础命令(1)--2019-11-14
    Linux系统的安装-2019-11-11
    Linux学习之路-基础入门 20191104
    linux下安装redis
    Hadoop(1):Centos 7 安装 Hadoop 3.2.1
    rsync 分发脚本
    Linux环境(Centos 7)安装MySQL数据库
    在已经安装好的Nginx上增加新模块
  • 原文地址:https://www.cnblogs.com/xiaochao-cs-whu/p/3960483.html
Copyright © 2011-2022 走看看