JavaScript中的命令模式

150 阅读3分钟

1.定义

命令模式是最简单和优雅的模式之一,命令模式中的命令(command)指的是一个执行某些特定事情的指令

2.使用场景

命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系

3.命令模式的例子

背景:餐厅点单 不使用命令模式写法

var bindClick = function (button, func) {
	button.onclick = func
}
var MenuBar = { 
    refresh: function(){ 
        console.log( '刷新菜单界面' ); 
    } 
}; 
 
var SubMenu = { 
    add: function(){ 
        console.log( '增加子菜单' ); 
    }, 
    del: function(){ 
        console.log( '删除子菜单' ); 
    } 
}; 
 
bindClick( button1, MenuBar.refresh ); 
bindClick( button2, SubMenu.add ); 
bindClick( button3, SubMenu.del );

这种情况的代码如果要实现撤销,排队等操作会比较麻烦,这个时候可以用命令模式来实现 如何使用命令模式来重构代码? 命令模式将过程式的请求调用封装在 command 对象的 execute 方法里,通过封装方法调用,我们可以把运算块包装成形。command 对象可以被四处传递,所以在调用命令的时候,客户(Client)不需要关心事情是如何进行的 命令模式的写法

var setCommand = function (button, command) {
  button.onclick = function () {
    command.execute();
  };
};

var MenuBar = {
  refresh: function () {
    console.log("刷新菜单界面");
  },
};

var RefreshMenuBarCommand = function (receiver) {
  return {
    execute: function () {
      receiver.refresh();
    },
  };
};

var refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar);

var button = document.querySelector("button");
setCommand(button, refreshMenuBarCommand);

4.撤销命令

命令模式的作用不仅是封装运算块,而且可以很方便地给命令对象增加撤销操作。 撤销操作的实现一般是给命令对象增加一个名为unexecude 或者undo 的方法,在该方法里执行execute 的反向操作

  • 生成一个历史命令对象,用来存放每一个命令的执行
  • 在执行execute时把当前执行的命令中的一些值,放在历史命令对象中
  • 在执行撤销操作时,执行unexecude方法,去执行历史命令对象中的值

5.重做

对于一些不容易实现的撤销功能,可以利用一个历史列表堆栈来存放执行过的所有命令,然后再点击重做时,将之前的全部取消,然后依次执行这个历史列表堆栈来实现重做功能

6.宏命令

宏命令是一组命令的集合,通过执行宏命令的方式,可以一次执行一批命令。

场景:想象一下,家里有一个万能遥控器,每天回家的时候,只要按一个特别的按钮,它就会帮我们关上房间门,顺便打开电脑并登录QQ。

var closeDoorCommand = {
  execute: function () {
    console.log("关门");
  },
};

var openPcCommand = {
  execute: function () {
    console.log("打开电脑");
  },
};

var openQQCommand = {
  execute: function () {
    console.log("打开QQ");
  },
};

var MarcoCommand = function () {
  return {
    commandList: [],
    add: function (command) {
      this.commandList.push(command);
    },
    execute: function () {
      for (var i = 0, command; (command = this.commandList[i++]); ) {
        command.execute();
      }
    },
  };
};

var marcoCommand = MarcoCommand();
marcoCommand.add(closeDoorCommand);
marcoCommand.add(openPcCommand);
marcoCommand.add(openQQCommand);
marcoCommand.execute();

当然我们还可以为宏命令添加撤销功能,跟 macroCommand.execute 类似,当调用macroCommand.undo 方法时,宏命令里包含的所有子命令对象要依次执行各自的undo 操作。 宏命令是命令模式与组合模式的联用产物

7.总结

JavaScript 可以用高阶函数非常方便地实现命令模式。命令模式在JavaScript 语言中是一种隐形的模式