1. 执行命令时,发布者执行者 分开,中间加入命令对象,作为中转站;

  2. 适用场景:

    • 解耦发送者与接收者:请求发送者请求接收者( 执行者 ) 需要 解耦发送者接收者 之间 不直接进行交互;
    • 抽象行为:需要将 等待执行 的行为 抽象出来;
  3. 优点:

    • 降低耦合:将 请求调用者请求接收者 进行 解耦
    • 扩展性高:如果要 扩展新命令,直接 定义 新的命令对象 即可;如果要 执行一组命令,发送一组命令 给接收者 即可;
  4. 缺点:

    • 增加复杂度:扩展命令导致 类的数量增加,增加了 系统实现的复杂程度
    • 需要针对每个命令,都要开发一个与之对应的命令类;

类图

三种角色

  • Receiver 接受者角色:该角色就是干活的角色,命令传递到这里是应该被执行的;
  • Command 命令角色:需要执行的所有命令都在这里声明;
  • Invoker 调用者角色:接收到命令,并执行命令;

代码

// 接受者角色
class Cooker {
  cook() {
    console.log(`做饭`);
  }
}
// 接受者角色
class Cleaner {
  clean() {
    console.log(`清洁`);
  }
}

// 命令角色
class CookCommand {
  constructor(cooker) {
    this.cooker = cooker;
  }
  execute() {
    this.cooker.cook();
  }
}
// 命令角色
class CleanCommand {
  constructor(cleaner) {
    this.cleaner = cleaner;
  }
  execute() {
    this.cleaner.clean();
  }
}

// 命令角色
class Customer {
  constructor(command) {
    this.command = command;
  }
  cook() {
    this.command.execute();
  }
  clean() {
    this.command.execute();
  }
}


let command = new CookCommand(new Cooker());
let c = new Customer(command);
c.cook();

command = new CleanCommand(new Cleaner());
c = new Customer(command);
c.clean();

应用场景

计数器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计数器</title>
</head>

<body>
    <p id="number">0</p>
    <button id="addBtn">点击按钮</button>
    <script>
        let addBtn = document.getElementById('addBtn');
        let number = document.getElementById('number');

        // 接收者
        let worker = {
            add() {
                number.innerHTML = parseInt(number.innerHTML) + 1;
            }
        }

        // 命令
        class AddCommand {
            constructor(receiver) {
                this.receiver = receiver;
            }
            execute() {
                this.receiver.add();
            }
        }

        let addCommand = new AddCommand(worker);
        // 调用者
        addBtn.onclick = () => addCommand.execute();
    </script>
</body>

</html>

撤销和重做

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>弹出菜单</title>
</head>

<body>
    <p id="number">0</p>
    <button id="addBtn">add</button>
    <button id="undoBtn">undo</button>
    <script>
        let addBtn = document.getElementById('addBtn');
        let undoBtn = document.getElementById('undoBtn');
        let number = document.getElementById('number');

        let worker = {
            lastVal: -1,
            add() {
                let oldVal = parseInt(number.innerHTML);
                worker.lastVal = oldVal;
                number.innerHTML = oldVal + 1;
            },
            undo() {
                number.innerHTML = worker.lastVal;
            }
        }

        class AddCommand {
            constructor(receiver) {
                this.receiver = receiver;
            }
            execute() {
                this.receiver.add();
            }
        }
        let addCommand = new AddCommand(worker);

        class UndoCommand {
            constructor(receiver) {
                this.receiver = receiver;
            }
            execute() {
                this.receiver.undo();
            }
        }
        let undoCommand = new UndoCommand(worker);

        addBtn.onclick = () => addCommand.execute();
        undoBtn.onclick = () => undoCommand.execute();
    </script>
</body>

</html>

多步撤销和重做

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>弹出菜单</title>
</head>

<body>
    <p id="number">0</p>
    <button id="addBtn">add</button>
    <button id="undoBtn">undo</button>
    <button id="redoBtn">redo</button>
    <script>
        let addBtn = document.getElementById('addBtn');
        let undoBtn = document.getElementById('undoBtn');
        let redoBtn = document.getElementById('redoBtn');
        let number = document.getElementById('number');

        let worker = {
            history: [],
            index: -1,
            add() {
                let oldVal = parseInt(number.innerHTML);
                let newVal = oldVal + 1;
                worker.history.push(newVal);
                worker.index = worker.history.length - 1;
                number.innerHTML = newVal;
                console.log(worker);
            },
            undo() {
                if (worker.index - 1 >= 0) {
                    worker.index--;
                    number.innerHTML = worker.history[worker.index];
                    console.log(worker);
                }
            },
            redo() {
                if (worker.index + 1 < worker.history.length) {
                    worker.index++;
                    number.innerHTML = worker.history[worker.index];
                    console.log(worker);
                }
            }
        }

        class AddCommand {
            constructor(receiver) {
                this.receiver = receiver;
            }
            execute() {
                this.receiver.add();
            }
        }
        let addCommand = new AddCommand(worker);

        class UndoCommand {
            constructor(receiver) {
                this.receiver = receiver;
            }
            execute() {
                this.receiver.undo();
            }
        }
        let undoCommand = new UndoCommand(worker);

        class RedoCommand {
            constructor(receiver) {
                this.receiver = receiver;
            }
            execute() {
                this.receiver.redo();
            }
        }
        let redoCommand = new RedoCommand(worker);

        addBtn.onclick = () => addCommand.execute();
        undoBtn.onclick = () => undoCommand.execute();
        redoBtn.onclick = () => redoCommand.execute();
    </script>
</body>

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

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

粽子

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

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

了解更多

目录

  1. 1. 类图
  2. 2. 代码
  3. 3. 应用场景
    1. 3.1. 计数器
    2. 3.2. 撤销和重做
    3. 3.3. 多步撤销和重做