命令模式(Command Pattern)


1. 命令设计模式(Command Pattern)

1.1 基本介绍

  • 定义:将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或记录日志,以及支持可撤销的操作。

1.2 主要角色

  1. 命令(Command):声明了一个给所有具体命令类的抽象接口。

  2. 接收者(Receiver):真正执行命令的角色,那些具体的命令ConcreteCommand引用它,让它完成命令的执行

  3. 具体命令(ConcreteCommand)具体的执行命令,他们需要实现Command接口

    注意:该角色创建好时,一个具体命令和一个接收者就已经建立了联系。通过实现execute方法,来调用接收者的相应操作。execute()方法通常叫做执行方法。

  4. 调用者(Invoker):创建一个具体命令(ConcreteCommand)对象并确定其接收者,负责按照客户端的指令设置并执行命令。像命令的撤销,日志的记录等功能都要在此类中完成.

  5. 客户端(Client):创建一个具体命令(ConcreteCommand)对象并确定其接收者,以及调用具体命令的调用者(Invoker)。

1.3 使用场景及注意事项

1.3.1 使用场景
  1. 在某些场合,比如要对行为进行"记录、撤销/重做事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合,这是命令模式的使用场景。

  2. 命令模式的意图是将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。当需要将各种执行的动作抽象出来,使用时通过不同的参数来决定执行哪个对象

  3. 当要对操作过程记录日志,以便后期通过日志将操作过程重新做一遍时。

1.3.2 注意事项
  • Command 接口非常简单,通常只有一个execute方法,如果要支持撤销操作的话,再加一个unexecute方法。

  • 每个具体的命令类内部封装了实际执行命令的那个类(Recevier),或者那些类,以及执行需要的数据。

  • 每个具体命令类只完成一个请求,有多少个请求就有多少个命令。

  • Invoker类只认识接口Command,其他的都不认识 -----调用者和实现者分离

  • 客户端类负责生成具体命令,并通过Invoker组装执行。

1.4 优缺点

  • 优点

    1. 命令模式将行为调用者和各种行为分隔开,降低程序的耦合,便于程序扩展
    2. 命令模式将行为的具体实现封装起来,客户端无需关心行为的具体实现。
    3. 命令模式可为多种行为提供统一的调用入口,便于程序对行为的管理和控制。此外,很容易实现序列操作及实现回调系统。你把命令加到一个列表中,迭代执行就可以实现序列操作了。 因为Java不能将函数作为参数,此处我们可以将命令对象当做参数,而这个对象还可执行,所以就实现了回调功能。
  • 缺点

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

1.5 案例

  • 坤坤是一个在美国上高中的篮球热爱者,他想要向NBA的一些球星来学习篮球技术(Command)。因为坤坤是富哥,所以他直接找到了NBA官方(Client),因为坤坤给的实在太多了,所以直接派NBA总裁肖华(Invoker)来负责安排坤坤的学习课程。坤坤的篮球技术课主要分为三个模块,分别是扣篮(ConcreteCommand)三分(ConcreteCommand)运球(ConcreteCommand)。因此肖华给坤坤找了三位老师,分别是詹姆斯(Receiver)库里(Receiver)欧文(Receiver)

  • 具体代码实现如下:

    1. 命令(Command):Command

      public interface Command {
          void execute();
      }
      
    2. 接收者(Receiver):James、Curry、Irving

      public class James {
          public String dunk(){
              return "詹姆斯教你扣篮";
          }
      }
      
      public class Curry {
          public String shoot(){
              return "库里教你投篮";
          }
      }
      
      public class Irving {
          public String dribble(){
              return "欧文教你运球";
          }
      }
      
    3. 具体命令(ConcreteCommand):DunkCommand、ShootCommand、DribbleCommand

      public class DunkCommand implements Command{
          private James james;
      
          public DunkCommand(James james) {
              this.james = james;
          }
      
          @Override
          public void execute() {
      		System.out.println(james.dunk());
          }
      }
      
      public class ShootCommand implements Command{
          private Curry curry;
      
          public ShootCommand(Curry curry) {
              this.curry = curry;
          }
      
          @Override
          public void execute() {
      		System.out.println(curry.shoot());
          }
      }
      
      public class DribbleCommand implements Command{
          private Irving irving;
      
          public DribbleCommand(Irving irving) {
              this.irving = irving;
          }
      
          @Override
          public void execute() {
              System.out.println(irving.dribble());
          }
      }
      
    4. 调用者(Receiver):XiaoHuaInvoker

      public class XiaoHuaInvoker {
          private List<Command> commandList = new ArrayList<>();
          // 添加命令
          public void addCommands(Command command) {
              commandList.add(command);
          }
          // 执行命令
          public void executeCommand() {
              for (Command command : commandList) {
                  command.execute();
              }
          }
      }
      
    5. 客户端(Client):NBAClient

      public class NBAClient {
          public static void main(String[] args) {
              // 1.创建Invoker
              XiaoHuaInvoker xiaoHuaInvoker = new XiaoHuaInvoker();
      
              // 2.创建ConcreteCommand和Receiver,并建立联系
              DunkCommand dunkCommand = new DunkCommand(new James());
              ShootCommand shootCommand = new ShootCommand(new Curry());
              DribbleCommand dribbleCommand = new DribbleCommand(new Irving());
      
              // 3.Invoker调用ConcreteCommand
              xiaoHuaInvoker.addCommands(dunkCommand);
              xiaoHuaInvoker.addCommands(shootCommand);
              xiaoHuaInvoker.addCommands(dribbleCommand);
      
              xiaoHuaInvoker.executeCommand();
          }
      }
      /*
      詹姆斯教你扣篮
      库里教你投篮
      欧文教你运球
      */
      

参考博客:

  1. 深入理解设计模式(十):命令模式 - 一指流砂~ - 博客园 (cnblogs.com)
  2. 秒懂设计模式之命令模式(Command Pattern)_command pattern 设计模式_ShuSheng007的博客-CSDN博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值