网站首页框架图,住房住房和城乡建设部网站,响应式网站视频,网站关键词在哪里设置Javascript命令模式 1 什么是命令模式2 命令模式的例子—菜单程序3 JavaScript 中的命令模式4 撤销命令5 宏命令 1 什么是命令模式
在一个餐厅中#xff0c;当客人现场点餐或者打电话订餐时#xff0c;老板会把客人的需求写在清单上#xff0c;厨师会按照清单的顺序给客人炒… Javascript命令模式 1 什么是命令模式2 命令模式的例子—菜单程序3 JavaScript 中的命令模式4 撤销命令5 宏命令 1 什么是命令模式
在一个餐厅中当客人现场点餐或者打电话订餐时老板会把客人的需求写在清单上厨师会按照清单的顺序给客人炒菜有时餐厅还可以满足定时点餐比如x时间之后再上菜如果客人需要撤销订单可以直接打电话给餐厅。
这些记录着订餐信息的清单就是命令模式中的命令对象。
命令模式允许将功能请求封装为独立的对象并根据需要将其排队、记录、撤销或重做。该模式的核心是将请求与其调用者分离从而使命令对象独立于发送者和接收者。
在命令模式中有4个主要角色命令对象、客户端、接收者和调用者。命令对象封装了一个特定的功能请求而客户端创建命令对象并将其传递给调用者。调用者是负责执行命令的对象并将其发送给接收者执行所需的操作。
命令模式在Javascript中有很多应用场景例如撤销和重做功能、动态添加命令、撤销命令、实现编辑器、处理用户交互等。
对于订餐来说客人需要向厨师发送请求但是并不关心厨师的名字和联系方式也不知道厨师炒菜的方式和步骤。命令模式把客人订餐的请求封装成command对象这个对象可以在程序中被四处传递就像订单可以从服务员手中传到厨师的手中。这样一来客人不需要知道厨师的名字从而解开了请求调用者和请求接收者之间的耦合关系。
2 命令模式的例子—菜单程序
假设我们封装一个按钮组的组件每个按钮都有自己的click事件对于封装这个组件的人来说并不关心这个按钮点击之后接收者是什么对象也不知道接收者究竟会做什么这时我们可以借助命令对象的帮助以便解开按钮和负责具体行为对象之间的耦合首先是按钮组绘制
button idbutton1点击按钮1/button
button idbutton2点击按钮2/button
button idbutton3点击按钮3/button
scriptvar button1 document.getElementById(button1);var button2 document.getElementById(button2);var button3 document.getElementById(button3);
/script接下来定义setCommand函数setCommand函数负责往按钮上面安装命令。可以肯定的是点击按钮会执行某个command命令执行命令的动作被约定为调用command对象的execute()方法。
var setCommand function (button, command) {button.onclick function () {command.execute();};
};最后是按钮的点击事件点击按钮后分别由刷新菜单界面、增加子菜单和删除子菜单这几个功能这几个功能被分布在MenuBar和SubMenu这两个对象中
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();
};最后把命令接收者传入到command对象中并且把command对象安装到button上面
var refreshMenuBarCommand new RefreshMenuBarCommand(MenuBar);
var addSubMenuCommand new AddSubMenuCommand(SubMenu);
var delSubMenuCommand new DelSubMenuCommand(SubMenu);setCommand(button1, refreshMenuBarCommand);
setCommand(button2, addSubMenuCommand);
setCommand(button3, delSubMenuCommand);以上只是一个很简单的命令模式示例但从中可以看到我们是如何把请求发送者和请求接收 者解耦开的。
3 JavaScript 中的命令模式
也许我们会感到很奇怪所谓的命令模式看起来就是给对象的某个方法取了execute的名字。引入command对象和receiver这两个无中生有的角色无非是把简单的事情复杂化了即使不用什么模式用下面寥寥几行代码就可以实现相同的功能
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对象可以被四处传递所以在调用命令的时候客户不需要关心事情是如何进行的。
跟策略模式一样命令模式也早已融入到了JavaScript语言之中。运算块不一定要封装在command.execute方法中也可以封装在普通函数中。函数作为一等对象本身就可以被四处传递。即使我们依然需要请求“接收者”那也未必使用面向对象的方式闭包可以完成同样的功能。
4 撤销命令
下面利用策略模式中Animate类编写一个动画Animate类指路JavaScript策略模式
这个动画的表现是让页面上的正方形移动到水平方向的某个位置。现在页面中有一个input文本框和一个button按钮文本框中可以输入一些数字表示正方形移动后的水平位置正方形在用户点击按钮后立刻开始移动代码如下
div idball classball/div
请输入移动后的位置input idpos /
button idmoveBtn开始移动/button
scriptvar ball document.getElementById(ball);var pos document.getElementById(pos);var moveBtn document.getElementById(moveBtn);moveBtn.onclick function () {var animate new Animate(ball);animate.start(left, pos.value, 1000, strongEaseOut);};
/script.ball {position: absolute;background-color: pink;width: 50px;height: 50px;
}如果文本框输入200然后点击moveBtn按钮可以看到正方形顺利地移动到水平方向200px的位置。现在我们需要一个方法让它还原到开始移动之前的位置在页面上设计一个撤销按钮点击撤销按钮之后小球便能回到上一次的位置。
在给页面中增加撤销按钮之前先把目前的代码改为用命令模式实现
var ball document.getElementById(ball);
var pos document.getElementById(pos);
var moveBtn document.getElementById(moveBtn);var MoveCommand function (receiver, pos) {this.receiver receiver;this.pos pos;
};
MoveCommand.prototype.execute function () {this.receiver.start(left, this.pos, 1000, strongEaseOut);
};var moveCommand;
moveBtn.onclick function () {var animate new Animate(ball);moveCommand new MoveCommand(animate, pos.value);moveCommand.execute();
};接下来增加撤销按钮
div idball classball/div
请输入移动后的位置input idpos /
button idmoveBtn开始移动/button
button idcancelBtn撤销/button撤销操作的实现一般是给命令对象增加一个名为unexecude或者undo的方法在该方法里执行execute的反向操作。在command.execute方法让正方形开始真正运动之前我们需要先记录正方形的当前位置在unexecude或者undo操作中再让它回到刚刚记录下的位置代码如下
var ball document.getElementById(ball);
var pos document.getElementById(pos);
var moveBtn document.getElementById(moveBtn);
var cancelBtn document.getElementById(cancelBtn);var MoveCommand function (receiver, pos) {this.receiver receiver;this.pos pos;this.oldPos null;
};
MoveCommand.prototype.execute function () {this.receiver.start(left, this.pos, 1000, strongEaseOut);// 记录小球开始移动前的位置this.oldPos this.receiver.dom.getBoundingClientRect()[this.receiver.propertyName];
};
MoveCommand.prototype.undo function () {// 回到小球移动前记录的位置this.receiver.start(left, this.oldPos, 1000, strongEaseOut);
};var moveCommand;
moveBtn.onclick function () {var animate new Animate(ball);moveCommand new MoveCommand(animate, pos.value);moveCommand.execute();
};
cancelBtn.onclick function () {moveCommand.undo(); // 撤销命令
};现在通过命令模式轻松地实现了撤销功能。如果用普通的方法调用来实现也许需要每次都手工记录小球的运动轨迹才能让它还原到之前的位置。而命令模式中小球的原始位置在小球开始移动前已经作为command对象的属性被保存起来所以只需要再提供一个undo方法并且在undo方法中让小球回到刚刚记录的原始位置就可以了。
5 宏命令
宏命令是一组命令的集合通过执行宏命令的方式可以一次执行一批命令。
比如说家里有一个万能遥控器每天回家的时候只要按一个特别的按钮它就会帮我们关上房间门顺便打开电脑并登录游戏。
下面我们逐步创建一个宏命令首先我们依然要创建好各种Command
var closeDoorCommand {execute: function () {console.log(关门);},
};
var openPcCommand {execute: function () {console.log(开电脑);},
};
var openGameCommand {execute: function () {console.log(打开游戏);},
};接下来定义宏命令MacroCommandmacroCommand.add方法表示把子命令添加进宏命令对象当调用宏命令对象的execute方法时会迭代这一组子命令对象并且依次执行它们的execute方法
var MacroCommand function () {return {commandsList: [],add: function (command) {this.commandsList.push(command);},execute: function () {for (var i 0, command; (command this.commandsList[i]); ) {command.execute();}},};
};var macroCommand MacroCommand();macroCommand.add(closeDoorCommand);
macroCommand.add(openPcCommand);
macroCommand.add(openQQCommand);
macroCommand.execute();