• 将请求转换为一个独立的对象,这个对象包含与请求相关的所有信息。
  • 将动作的请求者从动作的执行者之间解耦出来,
    • 例如顾客点餐,不需要知道厨师是谁以及如何做饭的,只要将菜单交给服务员就行了。
  • 一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。

命令模式 - 图1

  1. 发送者 (Sender)——亦称 “触发者 (Invoker)”——
    1. 类负责对请求进行初始化,
    2. 其中必须包含一个成员变量来存储对于命令对象的引用。
    3. 发送者触发命令, 而不向接收者直接发送请求。
    4. 注意, 发送者并不负责创建命令对象: 它通常会通过构造函数从客户端处获得预先生成的命令。
    5. image.png
  2. 命令 (Command) 接口通常仅声明一个执行命令的方法。
    1. image.png
  3. 具体命令 (Concrete Commands) 会实现各种类型的请求。
    1. 具体命令自身并不完成工作, 而是会将调用委派给一个业务逻辑对象。 但为了简化代码, 这些类可以进行合并。
  4. 接收者 (Receiver) 类包含部分业务逻辑。
    1. 几乎任何对象都可以作为接收者。
    2. 绝大部分命令只处理如何将请求传递到接收者的细节, 接收者自己会完成实际的工作。
  5. 客户端 (Client) 会创建并配置具体命令对象。
    1. 客户端必须将包括接收者实体在内的所有请求参数传递给命令的构造函数
    2. 此后, 生成的命令就可以与一个或多个发送者相关联了。

例子:https://www.jianshu.com/p/5901e76a6348

  • 客户端角色(Client):创建一个具体命令ConcreteCommand对象并确定其接收者。
  • 命令角色(Command): 声明一个给所有具体命令类的抽象接口。
  • 具体命令角色(ConcreteCommand):定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法。
  • 请求者角色(Invoker):负责调用命令对象执行请求,相关的方法叫做行动方法。
  • 接收者角色(Receiver):负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

接受者代码:

  1. public class Receiver {
  2. /**
  3. * 真正执行命令相应的操作
  4. */
  5. public void action() {
  6. System.out.println("执行操作");
  7. }
  8. }

抽象命令代码:

  1. public interface Command {
  2. /**
  3. * 执行方法
  4. */
  5. void execute();
  6. }

具体命令代码:

  1. public class ConcreteCommand implements Command {
  2. /**
  3. * 持有相应的接收者对象
  4. */
  5. private Receiver receiver = null;
  6. /**
  7. * 构造方法
  8. * @param receiver
  9. */
  10. public ConcreteCommand(Receiver receiver) {
  11. this.receiver = receiver;
  12. }
  13. @Override
  14. public void execute() {
  15. //通常会转调接收者的形影方法,让接收者来真正执行功能
  16. receiver.action();
  17. }
  18. }

请求者角色:

  1. public class Invoker {
  2. /**
  3. * 持有命令对象
  4. */
  5. private Command command = null;
  6. /**
  7. * 构造方法
  8. * @param command
  9. */
  10. public Invoker(Command command) {
  11. this.command = command;
  12. }
  13. /**
  14. * 行动方法
  15. */
  16. public void action() {
  17. command.execute();
  18. }
  19. }

客户端角色:

  1. public class Client {
  2. public static void main(String[] args) {
  3. //创建接收者
  4. Receiver receiver = new Receiver();
  5. //创建命令对象,设定其接收者
  6. Command command = new ConcreteCommand(receiver);
  7. //创建请求者,把命令对象设置进去
  8. Invoker invoker = new Invoker(command);
  9. //执行方法
  10. invoker.action();
  11. }
  12. }

优点

  • 更松散的耦合
    命令模式是的发起命令的对象——客户端,和具体实现命令的对象——接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。
  • 更动态的控制
    命令模式把请求封装起来,可以动态的对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。
  • 很自然的复合命令
    命令模式中的命令对象能够很容易的组合成复合命令,也就是宏命令,从而是系统操作更简单,功能更强大。 是用一个list来管理命令集合

image.png
image.png

  • 更好的拓展性
    由于发起命令的对象和具体的实现完全解耦,因此拓展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。