15. 命令模式(Command)

问题:想把「操作」封装成对象,支持撤销、队列、日志等。

核心:每个操作是一个命令对象,包含执行和撤销方法。

class Light {
  #state = false;
  on()  { this.#state = true;  console.log('灯开了'); }
  off() { this.#state = false; console.log('灯关了'); }
}

class LightOnCommand {
  #light;
  constructor(light) { this.#light = light; }
  execute()    { this.#light.on(); }
  unexecute()  { this.#light.off(); }
}

class RemoteControl {
  #history = [];
  execute(command) {
    command.execute();
    this.#history.push(command);
  }
  undo() {
    this.#history.pop()?.unexecute();
  }
}

const remote = new RemoteControl();
const light = new Light();
remote.execute(new LightOnCommand(light)); // 灯开了
remote.undo();                             // 灯关了
package command

import "fmt"

type Command interface {
  Execute()
  Unexecute()
}

type Light struct{ state bool }

func (l *Light) On()  { l.state = true;  fmt.Println("灯开了") }
func (l *Light) Off() { l.state = false; fmt.Println("灯关了") }

type LightOnCommand struct{ light *Light }

func (c LightOnCommand) Execute()   { c.light.On() }
func (c LightOnCommand) Unexecute() { c.light.Off() }

type RemoteControl struct {
  history []Command
}

func (r *RemoteControl) Execute(cmd Command) {
  cmd.Execute()
  r.history = append(r.history, cmd)
}

func (r *RemoteControl) Undo() {
  if len(r.history) == 0 {
    return
  }
  cmd := r.history[len(r.history)-1]
  r.history = r.history[:len(r.history)-1]
  cmd.Unexecute()
}