命令模式核心解析

  1. 命令模式 (Command Pattern)
    1. 将「请求」封装成一个独立的对象 (命令对象),这个对象包含执行请求的所有信息 (比如接收者、执行方法、参数等),从而实现请求发送者 (调用者) 和请求执行者 (接收者) 的解耦;
    2. 可以用一个生动的比喻理解:
      • (调用者 / Invoker) 去餐厅点餐,只需要告诉服务员 (命令对象) “来一份宫保鸡丁”,不用自己去厨房做菜;
      • 服务员拿着点菜单 (命令),把需求传达给厨师 (接收者 / Receiver)
      • 厨师负责实际做菜 (执行命令)
      • 整个过程中,你 (调用者) 不用知道厨师是谁、怎么做菜,只需要和命令对象交互,实现了 “点餐请求” 和 “做菜执行” 的解耦;
  2. 类图:
  3. 设计代码:
    // ====================== 1. Command 命令接口(对应类图的Command) ======================
    /**
     * 点餐命令接口:所有菜品命令的统一规范
     */
    interface Command {
      // 执行命令(对应“做菜”动作)
      execute(): void;
    }
    
    // ====================== 2. Receiver 接收者(对应类图的Chef) ======================
    /**
     * 厨师:真正执行“做菜”的角色(接收者)
     */
    class Chef {
      /**
       * 做宫保鸡丁(具体业务逻辑)
       */
      public cookKungPaoChicken(): void {
        console.log("🍲 厨师:开始做宫保鸡丁,配料:鸡肉、花生米、干辣椒...");
        console.log("🍲 厨师:宫保鸡丁做好啦!");
      }
    
      /**
       * 做鱼香肉丝(具体业务逻辑)
       */
      public cookYuXiangShreddedPork(): void {
        console.log("🍜 厨师:开始做鱼香肉丝,配料:猪肉、木耳、胡萝卜...");
        console.log("🍜 厨师:鱼香肉丝做好啦!");
      }
    }
    
    // ====================== 3. ConcreteCommand 具体命令(对应类图的两个具体命令) ======================
    /**
     * 宫保鸡丁命令:绑定厨师,实现执行逻辑
     */
    class KungPaoChickenCommand implements Command {
      // 持有接收者(厨师)
      private chef: Chef;
    
      constructor(chef: Chef) {
        this.chef = chef;
      }
    
      // 执行命令:调用厨师的“做宫保鸡丁”方法
      execute(): void {
        console.log("📝 服务员:收到宫保鸡丁订单,通知厨师制作...");
        this.chef.cookKungPaoChicken();
      }
    }
    
    /**
     * 鱼香肉丝命令:绑定厨师,实现执行逻辑
     */
    class YuXiangShreddedPorkCommand implements Command {
      // 持有接收者(厨师)
      private chef: Chef;
    
      constructor(chef: Chef) {
        this.chef = chef;
      }
    
      // 执行命令:调用厨师的“做鱼香肉丝”方法
      execute(): void {
        console.log("📝 服务员:收到鱼香肉丝订单,通知厨师制作...");
        this.chef.cookYuXiangShreddedPork();
      }
    }
    
    // ====================== 4. Invoker 调用者(对应类图的Customer) ======================
    /**
     * 顾客:发起点餐请求的角色(调用者)
     */
    class Customer {
      // 持有当前订单命令
      private orderCommand?: Command;
    
      /**
       * 下单:设置要执行的命令
       * @param command 具体的菜品命令
       */
      public setOrder(command: Command): void {
        this.orderCommand = command;
        console.log("👤 顾客:我要下单啦!");
      }
    
      /**
       * 催单/确认下单:执行命令
       */
      public placeOrder(): void {
        if (this.orderCommand) {
          console.log("👤 顾客:麻烦快点上菜~");
          this.orderCommand.execute();
        } else {
          console.log("👤 顾客:还没点单呢!");
        }
      }
    }
    
    // ====================== 5. 测试运行(模拟餐厅点餐流程) ======================
    // 1. 创建接收者:厨师
    const chef = new Chef();
    
    // 2. 创建具体命令:宫保鸡丁、鱼香肉丝订单
    const kungPaoCommand = new KungPaoChickenCommand(chef);
    const yuXiangCommand = new YuXiangShreddedPorkCommand(chef);
    
    // 3. 创建调用者:顾客
    const customer = new Customer();
    
    // 4. 模拟点餐流程
    console.log("===== 第一次点餐:宫保鸡丁 =====");
    customer.setOrder(kungPaoCommand);
    customer.placeOrder();
    
    console.log("\n===== 第二次点餐:鱼香肉丝 =====");
    customer.setOrder(yuXiangCommand);
    customer.placeOrder();
    
    console.log("\n===== 未点单直接催单 =====");
    const emptyCustomer = new Customer();
    emptyCustomer.placeOrder();
    

常用使用场景

编辑器类操作(最典型)

  1. 场景:富文本编辑器、代码编辑器的撤销 / 重做、剪切 / 复制 / 粘贴操作;

  2. 实现代码:

    // 1. 命令接口
    interface EditorCommand {
      execute(): void;
    }
    
    // 2. 接收者:富文本编辑器核心逻辑
    class RichTextEditor {
      private content: string = "Hello World";
    
      // 加粗文本
      public bold(): void {
        this.content = `**${this.content}**`;
        console.log(`[加粗后] ${this.content}`);
      }
    
      // 斜体文本
      public italic(): void {
        this.content = `*${this.content}*`;
        console.log(`[斜体后] ${this.content}`);
      }
    
      public getContent() {
        return this.content;
      }
    }
    
    // 3. 具体命令:加粗命令
    class BoldCommand implements EditorCommand {
      private editor: RichTextEditor;
      constructor(editor: RichTextEditor) {
        this.editor = editor;
      }
      execute(): void {
        this.editor.bold();
      }
    }
    
    // 4. 具体命令:斜体命令
    class ItalicCommand implements EditorCommand {
      private editor: RichTextEditor;
      constructor(editor: RichTextEditor) {
        this.editor = editor;
      }
      execute(): void {
        this.editor.italic();
      }
    }
    
    // 5. 调用者:编辑器工具栏
    class EditorToolbar {
      private currentCommand?: EditorCommand;
    
      // 设置并执行命令
      public setCommand(command: EditorCommand): void {
        this.currentCommand = command;
        this.currentCommand.execute();
      }
    }
    
    // 测试代码
    const editor = new RichTextEditor();
    const toolbar = new EditorToolbar();
    
    console.log("===== 编辑器操作演示 =====");
    toolbar.setCommand(new BoldCommand(editor)); // 输出:[加粗后] **Hello World**
    toolbar.setCommand(new ItalicCommand(editor)); // 输出:[斜体后] ***Hello World***
    

按钮 / 菜单与业务逻辑解耦

  1. 场景:后台管理系统的操作按钮(新增 / 编辑 / 删除);

  2. 实现代码:

    // 1. 命令接口
    interface ActionCommand {
      execute(): Promise<void>; // 异步执行(模拟接口请求)
    }
    
    // 2. 接收者:用户管理业务逻辑
    class UserService {
      // 新增用户(模拟接口请求)
      public async addUser(username: string): Promise<void> {
        return new Promise(resolve => {
          setTimeout(() => {
            console.log(`[业务逻辑] 新增用户:${username}(模拟接口请求成功)`);
            resolve();
          }, 500);
        });
      }
    
      // 删除用户(模拟接口请求)
      public async deleteUser(id: number): Promise<void> {
        return new Promise(resolve => {
          setTimeout(() => {
            console.log(`[业务逻辑] 删除用户:ID=${id}(模拟接口请求成功)`);
            resolve();
          }, 500);
        });
      }
    }
    
    // 3. 具体命令:新增用户命令
    class AddUserCommand implements ActionCommand {
      private userService: UserService;
      private username: string;
    
      constructor(userService: UserService, username: string) {
        this.userService = userService;
        this.username = username;
      }
    
      async execute(): Promise<void> {
        await this.userService.addUser(this.username);
      }
    }
    
    // 4. 具体命令:删除用户命令
    class DeleteUserCommand implements ActionCommand {
      private userService: UserService;
      private userId: number;
    
      constructor(userService: UserService, userId: number) {
        this.userService = userService;
        this.userId = userId;
      }
    
      async execute(): Promise<void> {
        await this.userService.deleteUser(this.userId);
      }
    }
    
    // 5. 调用者:按钮组件(视图层)
    class Button {
      private command?: ActionCommand;
      private label: string;
    
      constructor(label: string) {
        this.label = label;
      }
    
      // 绑定命令
      public setCommand(command: ActionCommand): void {
        this.command = command;
      }
    
      // 模拟按钮点击
      public async onClick(): Promise<void> {
        console.log(`[视图层] 点击【${this.label}】按钮`);
        if (this.command) {
          await this.command.execute();
        } else {
          console.log(`[视图层] 【${this.label}】按钮未绑定命令`);
        }
      }
    }
    
    // 测试代码
    const userService = new UserService();
    
    // 创建按钮
    const addUserBtn = new Button("新增用户");
    const deleteUserBtn = new Button("删除用户");
    
    // 绑定命令
    addUserBtn.setCommand(new AddUserCommand(userService, "zhangsan"));
    deleteUserBtn.setCommand(new DeleteUserCommand(userService, 1001));
    
    // 模拟点击
    console.log("===== 按钮解耦演示 =====");
    await addUserBtn.onClick();
    // 输出:
    // [视图层] 点击【新增用户】按钮
    // [业务逻辑] 新增用户:zhangsan(模拟接口请求成功)
    
    await deleteUserBtn.onClick();
    // 输出:
    // [视图层] 点击【删除用户】按钮
    // [业务逻辑] 删除用户:ID=1001(模拟接口请求成功)
    

命令模式的优势

  1. 解耦:调用者和接收者完全解耦;

  2. 扩展性:新增命令无需修改现有代码;

  3. 组合性:支持宏命令和命令队列;

  4. 可撤销:轻松实现撤销/重做功能;

  5. 历史记录:可以记录操作日志;

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 命令模式核心解析
  2. 2. 常用使用场景
    1. 2.1. 编辑器类操作(最典型)
    2. 2.2. 按钮 / 菜单与业务逻辑解耦
  3. 3. 命令模式的优势