命令模式

# 命令模式

将请求转换为一个包含与请求相关的所有信息的独立对象

通俗来讲

类比

# 优点

  • 单一职责原则 可以解耦触发和执行操作的类.

  • 开闭原则 可以在不修改已有客户端代码的情况下在程序中创建新的命令.

  • 可以实现撤销和恢复功能

  • 可以实现操作的延迟执行

  • 可以将一组简单命令组合成一个复杂的命令

# 缺点

  • 代码变得更加复杂. 因为在发送者和接收者之间增加了一个全新的层次.

# 适用场景

  • 如果需要通过操作来参数化对象

    例如开发一个GUI组件(上下文菜单), 希望用户能够配置菜单项, 并在点击菜单项时触发操作.

  • 如果想要将操作放入队列中, 操作的执行或者远程执行操作

  • 如果想要实现操作回滚功能

# 实现

点击查看代码
interface Command {
  execute(): void;
}

class SimpleCommand implements Command {
  private payload: string;

  constructor(payload: string) {
    this.payload = payload;
  }

  public execute(): void {
    console.log(`SimpleCommand: See, I can do simple things like printing (${this.payload})`);
  }
}

class ComplexCommand implements Command {
  private receiver: Receiver;

  private a: string;
  private b: string;

  constructor(receiver: Receiver, a: string, b: string) {
    this.receiver = receiver;
    this.a = a;
    this.b = b;
  }

  public execute(): void {
    console.log(`ComplexCommandL Complex stuff should be done by a receiver object.`);
    this.receiver.doSomething(this.a);
    this.receiver.doSomethingElse(this.b);
  }
}

class Receiver {
  public doSomething(a: string): void {
    console.log(`Receiver: Working on (${a})`);
  }

  public doSomethingElse(b: string): void {
    console.log(`Receiver: Also working on (${b})`);
  }
}

class Invoker {
  private onStart!: Command;
  private onFinish!: Command;

  public setOnStart(command: Command): void {
    this.onStart = command;
  }

  public setonFinish(command: Command): void {
    this.onFinish = command;
  }

  public doSomethingImportant(): void {
    console.log(`Invoker: Does anybody want something done before I begin?`);

    if (this.isCommand(this.onStart)) {
      this.onStart.execute();
    }

    console.log(`Invoker: ...doing something really important...`);
    
    console.log(`Invoker: Does anybody want something done after I finish?`);
    if (this.isCommand(this.onFinish)) {
      this.onFinish.execute();
    }
  }

  private isCommand(object: Command) {
    return object.execute !== undefined;
  }
}

const invoker = new Invoker();
invoker.setOnStart(new SimpleCommand("Say Hi!"));
const receiver = new Receiver();
invoker.setonFinish(new ComplexCommand(receiver, "Send email", "Save report"));

invoker.doSomethingImportant();

// output:
// Invoker: Does anybody want something done before I begin?
// SimpleCommand: See, I can do simple things like printing (Say Hi!)
// Invoker: ...doing something really important...
// Invoker: Does anybody want something done after I finish?
// ComplexCommand: Complex stuff should be done by a receiver object.
// Receiver: Working on (Send email)
// Receiver: Also working on (Save report)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93