饭店吃饭时,客人点完菜后,订单会交给后厨出菜。
订单就是命令对象,被四处传递。
客人不需要认识厨师,等于命令调用者和命令接受者解耦。
<button id="btn1">click 1</button>
<button id="btn2">click 2</button>
<button id="btn3">click 3</button>
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
var btn3 = document.getElementById('btn3');
// 命令分发
var setCommand = function (button, command) {
button.onclick = function () {
command.execute();
};
};
var MenuBar = {
refresh: function () {
console.log('刷新菜单目录');
}
};
var SubMenu = {
add: function () {
console.log('增加子菜单');
},
del: function () {
console.log('删除子菜单');
}
};
// 命令类
var RefreshMenuBarCommand = function (receiver) {
this.receiver = receiver;
};
RefreshMenuBarCommand.prototype.execute = function () {
this.receiver.refresh();
};
var AddSubMenuCommand = function (receiver) {
this.receiver = receiver;
};
AddSubMenuCommand.prototype.execute = function () {
this.receiver.add();
};
var DelSubMenuCommand = function (receiver) {
this.receiver = receiver;
};
DelSubMenuCommand.prototype.execute = function () {
this.receiver.del();
};
var refreshCommand = new RefreshMenuBarCommand(MenuBar);
var addCommand = new AddSubMenuCommand(SubMenu);
var delCommand = new DelSubMenuCommand(SubMenu);
setCommand(btn1, refreshCommand);
setCommand(btn2, addCommand);
setCommand(btn3, delCommand);
JavaScript code
// 命令发送者 -- 吃饭的客人
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
var btn3 = document.getElementById('btn3');
// 命令接受者 -- 厨师
var MenuBar = {
refresh: function () {
console.log('刷新菜单目录');
}
};
var SubMenu = {
add: function () {
console.log('增加子菜单');
},
del: function () {
console.log('删除子菜单');
}
};
// 分发命令 -- 服务员
var setCommand = function (button, command) {
button.onclick = function () {
command.execute();
};
};
// 命令类 -- 订单
var RefreshMenuBarCommand = function (receiver) {
return {
execute: function () {
receiver.refresh();
}
};
};
var AddSubMenuCommand = function (receiver) {
return {
execute: function () {
receiver.add();
}
};
};
var DelSubMenuCommand = function (receiver) {
return {
execute: function () {
receiver.del();
}
};
};
// 命令实例 -- 菜单
var refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar);
var addSubMenuCommand = AddSubMenuCommand(SubMenu);
var delSubMenuCommand = DelSubMenuCommand(SubMenu);
// 完成点单
setCommand(btn1, refreshMenuBarCommand);
setCommand(btn2, addSubMenuCommand);
setCommand(btn3, delSubMenuCommand);
宏命令
宏命令有execute方法,宏命令里的每条命令都有execute方法。
执行宏命令的时候,只需执行每条命令的execute方法
var closeDoorCommand = {
execute: function () {
console.log('关门');
}
};
var openPcCommand = {
execute: function () {
console.log('开电脑');
}
};
var openQqCommand = {
execute: function () {
console.log('登录QQ');
}
};
var MacroCommand = function () {
var commandList = [];
var add = function (command) {
commandList.push(command);
};
var execute = function () {
for (let i = 0; i < commandList.length; i++) {
const command = commandList[i];
command.execute();
}
};
return {
add,
execute
};
};
var macroCommand = MacroCommand();
macroCommand.add(closeDoorCommand);
macroCommand.add(openPcCommand);
macroCommand.add(openQqCommand);
macroCommand.execute();
还可以为宏命令添加撤销功能,跟macroCommand.execute类似,当调用macroCommand.undo方法时,宏命令里包含的所有子命令对象要依次执行各自的undo操作。
智能命令与傻瓜命令
closeDoorCommand中没有包含任何receiver的信息,它本身就包揽了执行请求的行为,这跟我们之前看到的命令对象都包含了一个receiver是矛盾的。
一般来说,命令模式都会在command对象中保存一个接收者来负责真正执行客户的请求,这种情况下命令对象是“傻瓜式”的,它只负责把客户的请求转交给接收者来执行,这种模式的好处是请求发起者和请求接收者之间尽可能地得到了解耦。
但是我们也可以定义一些更“聪明”的命令对象,“聪明”的命令对象可以直接实现请求,这样一来就不再需要接收者的存在,这种“聪明”的命令对象也叫作智能命令。没有接收者的智能命令,退化到和策略模式非常相近,从代码结构上已经无法分辨它们,能分辨的只有它们意图的不同。策略模式指向的问题域更小,所有策略对象的目标总是一致的,它们只是达到这个目标的不同手段,它们的内部实现是针对“算法”而言的。而智能命令模式指向的问题域更广,command对象解决的目标更具发散性。命令模式还可以完成撤销、排队等功能