美文网首页
19、命令模式(Command Pattern)

19、命令模式(Command Pattern)

作者: 火山_6c7b | 来源:发表于2020-08-25 17:53 被阅读0次

    1. 命令模式

    1.1 简介

      命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

      将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。 (来自《设计模式之禅》)

    1.2 结构

    Command模式uml:

    Command模式uml.jpg

    Command模式角色:

    • Command:定义命令的接口,声明执行的方法。
    • ConcreteCommand: 具体的命令, 实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
    • Receiver:接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
    • Invoker:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
    • Client: 创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。

    2. 示例

      司令员下令让士兵去干件事情,从整个事情的角度来考虑,司令员的作用是,发出口令,口令经过传递,传到了士兵耳朵里,士兵去执行。这个过程好在,三者相互解耦,任何一方都不用去依赖其他人,只需要做好自己的事儿就行,司令员要的是结果,不会去关注到底士兵是怎么实现的。

      Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象。

    ** Command:**

    public interface Command {  
       public void exe();  
    }
    

    ** MyCommand:**

    public class MyCommand implements Command {  
     
       private Receiver receiver;  
         
       public MyCommand(Receiver receiver) {  
           this.receiver = receiver;  
       }  
     
       @Override  
       public void exe() {  
           receiver.action();  
       }  
    }  
    

    ** Receiver:**

    public class Receiver {  
       public void action(){  
           System.out.println("command received!");  
       }  
    } 
    

    ** Invoker:**

    public class Invoker {  
         
       private Command command;  
         
       public Invoker(Command command) {  
           this.command = command;  
       }  
     
       public void action(){  
           command.exe();  
       }  
    }  
    

    ** 调用示例:**

       public static void main(String[] args) {  
           Receiver receiver = new Receiver();  
           Command cmd = new MyCommand(receiver);  
           Invoker invoker = new Invoker(cmd);  
           invoker.action();  
       } 
    

    3. 总结

      命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开,熟悉Struts的同学应该知道,Struts其实就是一种将请求和呈现分离的技术,其中必然涉及命令模式的思想!

    命令模式优点:

    • 降低了系统耦合度。
    • 命令模式的封装性很好:每个命令都被封装起来,对于客户端来说,需要什么功能就去调用相应的命令,而无需知道命令具体是怎么执行的。比如有一组文件操作的命令:新建文件、复制文件、删除文件。如果把这三个操作都封装成一个命令类,客户端只需要知道有这三个命令类即可,至于命令类中封装好的逻辑,客户端则无需知道。
    • 命令模式的扩展性很好,在命令模式中,在接收者类中一般会对操作进行最基本的封装,命令类则通过对这些基本的操作进行二次封装,当增加新命令的时候,对命令类的编写一般不是从零开始的,有大量的接收者类可供调用,也有大量的命令类可供调用,代码的复用性很好。比如,文件的操作中,我们需要增加一个剪切文件的命令,则只需要把复制文件和删除文件这两个命令组合一下就行了,非常方便。
    • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
    • 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。
    • 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。

    命令模式缺点:

    • 使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

    命令模式适用场景:

    • struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
    • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
    • 系统需要在不同的时间指定请求、将请求排队和执行请求。
    • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
    • 系统需要将一组操作组合在一起,即支持宏命令。

    相关文章

      网友评论

          本文标题:19、命令模式(Command Pattern)

          本文链接:https://www.haomeiwen.com/subject/jrxojktx.html