TIP

命令模式中的命令指的是一个执行某些特定事情的指令。

# JavaScript中的命令模式

命令模式的由来,其实是回调函数的一个面向对象的替代品。和策略模式一样,命令模式也早已融入到了JavaScript语言中。

案例:菜单程序 假设我们正在编写一个用户界面程序,该用户界面上至少有数十个Button按钮。因为项目比价复杂,所以我们决定让某个程序员负责绘制这些按钮,而另外一些程序员则负责编写点击按钮后的具体行为,这些行为都将被封装在对象里。

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

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

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

var refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar)

setCommand(button1, refreshMenuBarCommand)

# 撤销和重做

当需要撤销命令时,我们可以把所有执行过的命令都存储在一个历史列表中,然后倒序循环来依次执行这些命令的undo操作。
如果要撤销不可逆转的命令,我们可以记录命令日志,然后清楚搜索操作,把刚才执行过的命令全部重新执行一遍。

var Ryu = {
  attack () {
    console.log("攻击");
	},
	
  defense () {
    console.log("防御");
  },
						
	jump () {
    console.log("跳跃");
  },
						
	crouch () {
    console.log("蹲下")
  }
}
				
var makeCommand = function (receiver, state) {
  return function () {
    if (receiver[state]) {
      receiver[state]();
    }
	}
}
				
const commands = {
  "119": "jump",
  "115": "crouch",
  "97": "defense",
  "100": "attack"
}
				
var commandStack = [];

document.onkeypress = function (ev) {
  var keyCode = ev.keyCode,
    command = makeCommand(Ryu, commands[keyCode]);
  if (command) {
    commandStack.push(command);
  }
}
	
document.getElementById("replay").onclick = function () {
  var command;
  while (command = commandStack.shift()) {
    command();
  }
}

# 宏命令

TIP

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

var closeDoorCommand = {
  excute: function () {
    console.log("关门");
  }
}
				
var openPcCommand = {
  excute: function () {
    console.log("开电脑");
  }
}

var openQQCommand = {
  excute: function () {
    console.log("登陆qq")
	}
}
				
var macroCommand = (function () {
  return {
		commandList: [],
		
    add: function (command) {
      this.commandList.push(command);
		},
		
    excute: function () {
      for (var i = 0, command; command = this.commandList[i++];) {
        command.excute();
    	}
		}
  }
})()

macroCommand.add(closeDoorCommand);
macroCommand.add(openPcCommand);
macroCommand.add(openQQCommand);
macroCommand.excute();