Javascript命令模式

Javascript命令模式

  • 1 什么是命令模式
  • 2 命令模式的例子—菜单程序
  • 3 JavaScript 中的命令模式
  • 4 撤销命令
  • 5 宏命令

1 什么是命令模式

在一个餐厅中,当客人现场点餐或者打电话订餐时,老板会把客人的需求写在清单上,厨师会按照清单的顺序给客人炒菜,有时餐厅还可以满足定时点餐,比如x时间之后再上菜,如果客人需要撤销订单,可以直接打电话给餐厅。

这些记录着订餐信息的清单,就是命令模式中的命令对象

命令模式允许将功能请求封装为独立的对象,并根据需要将其排队、记录、撤销或重做。该模式的核心是将请求与其调用者分离,从而使命令对象独立于发送者和接收者。

在命令模式中,有4个主要角色:命令对象、客户端、接收者和调用者。命令对象封装了一个特定的功能请求,而客户端创建命令对象并将其传递给调用者。调用者是负责执行命令的对象,并将其发送给接收者执行所需的操作。

命令模式在Javascript中有很多应用场景,例如撤销和重做功能、动态添加命令、撤销命令、实现编辑器、处理用户交互等。

对于订餐来说,客人需要向厨师发送请求,但是并不关心厨师的名字和联系方式,也不知道厨师炒菜的方式和步骤。命令模式把客人订餐的请求封装成command对象,这个对象可以在程序中被四处传递,就像订单可以从服务员手中传到厨师的手中。这样一来,客人不需要知道厨师的名字,从而解开了请求调用者和请求接收者之间的耦合关系。

2 命令模式的例子—菜单程序

假设我们封装一个按钮组的组件,每个按钮都有自己的click事件,对于封装这个组件的人来说,并不关心这个按钮点击之后接收者是什么对象,也不知道接收者究竟会做什么,这时我们可以借助命令对象的帮助,以便解开按钮和负责具体行为对象之间的耦合,首先是按钮组绘制:

<button id="button1">点击按钮1</button>
<button id="button2">点击按钮2</button>
<button id="button3">点击按钮3</button>
<script>var 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();};
};

最后是按钮的点击事件,点击按钮后分别由刷新菜单界面、增加子菜单和删除子菜单这几个功能,这几个功能被分布在MenuBarSubMenu这两个对象中:

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 id="ball" class="ball"></div>
请输入移动后的位置:<input id="pos" />
<button id="moveBtn">开始移动</button>
<script>var 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 id="ball" class="ball"></div>
请输入移动后的位置:<input id="pos" />
<button id="moveBtn">开始移动</button>
<button id="cancelBtn">撤销</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();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/167422.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

驱动开发3 ioctl函数的使用+3个实例(不传递第三个参数、第三个参数为整型、第三个参数为地址)

开发板&#xff1a;stm32mp157aaa&#xff08;Cortex-A7*2 Cortex-M4*1&#xff09;开发环境&#xff1a;vscode、串口工具 1 引入ioctl函数的意义 linux操作系统中有意将数据的读写和读写功能的选择分别交给不同的函数去完成。就让read/write函数只进行数据的读写即可&#x…

多版本并发控制MVCC

什么是MVCC MVCC &#xff08;Multiversion Concurrency Control&#xff09;&#xff0c;多版本并发控制。顾名思义&#xff0c;MVCC 是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之&#xff0c;…

SolidWorks模型导入到Gazebo中

首先建立好solidworks模型&#xff0c;然后另存为stl格式&#xff0c; 导出为STL文件时&#xff0c;文件名最好不要是中文&#xff0c;并且要将后缀STL改为stl&#xff0c;否则Gazebo无法识别 这是我创建好的机器人充电桩模型&#xff1a; 尺寸是单位是mm&#xff1a; 135mm …

【图像误差测量】测量 2 张图像之间的差异,并测量图像质量(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

图论06-【无权无向】-图的遍历并查集Union Find-力扣695为例

文章目录 1. 代码仓库2. 思路2.1 UF变量设计2.2 UF合并两个集合2.3 查找当前顶点的父节点 find(element) 3. 完整代码 1. 代码仓库 https://github.com/Chufeng-Jiang/Graph-Theory 2. 思路 2.1 UF变量设计 parent数组保存着每个节点所指向的父节点的索引&#xff0c;初始值为…

面向对象(基础)特征一:封装性(encapsulation)

文章目录 一、介绍&#xff08;1&#xff09;封装性&#xff08;2&#xff09;权限修饰符 二、案例&#xff08;1&#xff09;案例1 三、练习&#xff08;1&#xff09;练习1&#xff08;2&#xff09;练习2&#xff08;3&#xff09;练习3&#xff08;4&#xff09;练习4 面向…

数据丢失恢复怎么操作好?五种方法帮您恢复数据

丢失文件可能会造成灾难性的后果&#xff0c;因此您绝对需要最好的 PC 恢复软件。数据恢复软件必须快速、可靠并涵盖大多数文件格式。我们列表中最好的工具是一个甚至可以检索隐藏文件的解决方案。我们选择的另一个解决方案能够恢复700 多种独特的文件格式。 这种噩梦可能发生…

【PyTorch实战演练】自调整学习率实例应用(附代码)

目录 0. 前言 1. 自调整学习率的常用方法 1.1 ExponentialLR 指数衰减方法 1.2 CosineAnnealingLR 余弦退火方法 1.3 ChainedScheduler 链式方法 2. 实例说明 3. 结果说明 3.1 余弦退火法训练过程 3.2 指数衰减法训练过程 3.3 恒定学习率训练过程 3.4 结果解读 4. …

华为OD机试 - 代表团坐车 - 动态规划(Java 2023 B卷 200分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#…

人工智能(5):深度学习简介

1 深度学习 —— 神经网络简介 深度学习&#xff08;Deep Learning&#xff09;&#xff08;也称为深度结构学习【Deep Structured Learning】、层次学习【Hierarchical Learning】或者是深度机器学习【Deep Machine Learning】&#xff09;是一类算法集合&#xff0c;是机器学…

Jenkins+Ant+Jmeter接口自动化集成测试

一、Jenkins安装配置 1、安装配置JDK1.6环境变量&#xff1b; 2、下载jenkins.war&#xff0c;放入C:\jenkins目录下&#xff0c;目录位置随意&#xff1b; Jenkins启动方法&#xff1a; cmd进入Jenkins目录下&#xff0c;执行java -jar jenkins.war 浏览器输入&#xff1a;l…

html5语义化标签

目录 前言 什么是语义化标签 常见的语义化标签 语义化的好处 前言 HTML5 的设计目的是为了在移动设备上支持多媒体。之前网页如果想嵌入视频音频&#xff0c;需要用到 flash &#xff0c;但是苹果设备是不支持 flash 的&#xff0c;所以为了改变这一现状&#xff0c;html5 …

解决 Element-ui中 表格(Table)使用 v-if 条件控制列显隐时数据展示错乱的问题

本文 Element-ui 版本 2.x 问题 在 el-table-column 上需根据不同 v-if 条件来控制列显隐时&#xff0c;就会出现列数据展示错乱的情况&#xff08;要么 A 列的数据显示在 B 列上&#xff0c;或者后端返回有数据的但是显示的为空&#xff09;&#xff0c;如下所示。 <tem…

使用screen实现服务器代码一直运行

1.安装screen sudo apt install screen 2.创建一个screen&#xff08;创建一个名为chatglm的新的链接&#xff0c;用来一直运行 screen -S chatglm 3.查看进程列表 screen -ls 创建之后&#xff0c;就可以在当前窗口利用cd命令进入要执行的项目中&#xff0c;开始执行&#xf…

pow函数

pow函数 pow的翻译是指数表达式 第一个参数为底数&#xff0c;第二个参数为指数 返回值为&#xff1a; 头文件为include <math.h> #include <stdio.h> #include <math.h>int main() {int ret (int)pow(10, 2);printf("%d\n", ret);return 0; }…

分享一下我家网络机柜,家庭网络设备推荐

家里网络机柜搞了几天终于搞好了&#xff0c;非专业的&#xff0c;走线有点乱&#xff0c;勿喷。 从上到下的设备分别是&#xff1a; 无线路由器&#xff08;当ap用&#xff09;:TL-XDR6088 插排&#xff1a;德木pdu机柜插排 硬盘录像机&#xff1a;TL-NVR6108-L8P 第二排左边…

云计算认证有哪些?认证考了有什么用?

云计算作为一项快速发展的技术&#xff0c;对人才的需求持续增长。无论是男生还是女生&#xff0c;只要具备相关的技能和知识&#xff0c;都可以在云计算领域找到就业机会。 目前入行云计算最好最便捷的方式就是考证&#xff0c;拿到一个云计算相关的证书&#xff0c;就能开启…

2023最新UI酒桌喝酒游戏小程序源码 娱乐小程序源码 带流量主

2023最新UI酒桌喝酒游戏小程序源码 娱乐小程序源码 带流量主 修改增加了广告位&#xff0c;根据文档直接替换&#xff0c;原版本没有广告位 直接上传源码到开发者端即可 通过后改广告代码&#xff0c;然后关闭广告展示提交&#xff0c;通过后打开即可 无广告引流 流量主版…

No171.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

SD NAND对比TF卡优势(以CSNP4GCR01-AMW为例)

最近做的一个项目&#xff0c; 需要加大容量存储&#xff0c;这让我想到之前在做ARM的开发板使用的TF卡方案&#xff0c;但是TF卡需要携带卡槽的&#xff0c;但是有限的PCB板布局已经放不下卡槽的位置。 这个时候就需要那种能够不用卡槽&#xff0c;直接贴在板子上面&#xff0…