cover

Command 模式:可排程的操作封裝

Command 模式把操作包成獨立物件,可用於排隊、撤銷、記錄等情境。

classDiagram
    class Invoker {
        -history : Command[]
        +executeCommand(command) void
    }
    class Command {
        <<abstract>>
        +execute()* void
    }
    class SubmitRequestCommand {
        -receiver : WorkflowReceiver
        -requestId : String
        +execute() void
    }
    class ApproveRequestCommand {
        -receiver : WorkflowReceiver
        -requestId : String
        +execute() void
    }
    class WorkflowReceiver {
        +submit(requestId) void
        +approve(requestId) void
        +execute(requestId) void
    }
    Invoker o-- Command : 執行與記錄
    Command <|-- SubmitRequestCommand
    Command <|-- ApproveRequestCommand
    SubmitRequestCommand --> WorkflowReceiver
    ApproveRequestCommand --> WorkflowReceiver

使用情境

  1. 工作流程系統:提交、審核、執行。
  2. 撤銷/重做:文字編輯或繪圖工具。
  3. 批次操作:排程或佇列處理。

實作範例

Command 模式:命令佇列與執行歷史

class WorkflowReceiver {
  submit(requestId) {
    console.log(`Request ${requestId} submitted`);
  }
 
  approve(requestId) {
    console.log(`Request ${requestId} approved`);
  }
 
  execute(requestId) {
    console.log(`Request ${requestId} executed`);
  }
}
 
class Command {
  execute() {
    throw new Error('execute must be implemented');
  }
}
 
class SubmitRequestCommand extends Command {
  constructor(receiver, requestId) {
    super();
    this.receiver = receiver;
    this.requestId = requestId;
  }
 
  execute() {
    this.receiver.submit(this.requestId);
  }
}
 
class ApproveRequestCommand extends Command {
  constructor(receiver, requestId) {
    super();
    this.receiver = receiver;
    this.requestId = requestId;
  }
 
  execute() {
    this.receiver.approve(this.requestId);
  }
}
 
class Invoker {
  constructor() {
    this.history = [];
  }
 
  executeCommand(command) {
    command.execute();
    this.history.push(command);
  }
}
 
const receiver = new WorkflowReceiver();
const invoker = new Invoker();
 
invoker.executeCommand(new SubmitRequestCommand(receiver, 'REQ-001'));
invoker.executeCommand(new ApproveRequestCommand(receiver, 'REQ-001'));

優點

  • 降低呼叫端耦合
  • 容易實作撤銷與排程
  • 可記錄操作歷史

缺點

  • 命令類別數量增加

延伸閱讀