您现在的位置是:亿华云 > 域名
面试官:说说你对命令模式的理解?应用场景?
亿华云2025-10-03 20:33:51【域名】2人已围观
简介本文转载自微信公众号「JS每日一题」,作者灰灰 。转载本文请联系JS每日一题公众号。一、是什么命令模式是最简单和优雅的模式之一,命令模式中的命令指的是一个执行某些特定事情的指令该模式旨在将函数的调用、
本文转载自微信公众号「JS每日一题」,面试命令模式作者灰灰 。官说转载本文请联系JS每日一题公众号。说对
一、解应景是用场什么
命令模式是最简单和优雅的模式之一,命令模式中的面试命令模式命令指的是一个执行某些特定事情的指令
该模式旨在将函数的调用、请求和操作封装成为一个单一的官说对象
请求以命令的形式包裹在对象中,并传给调用对象。说对调用对象寻找可以处理该命令的解应景合适的对象,并把该命令传给相应的用场对象,该对象执行命令
例如在一个快餐店,面试命令模式用户向服务员点餐。官说服务员将用户的说对需求记录在清单上:
请求者点菜:参数是菜名(我要什么菜),时间(什么时候要),解应景该需求封装起来后,用场如果有变化我可以修改参数 命令模式将点餐内容封装成为命令对象,命令对象就是填写的清单 用户不知道接收者(厨师)是网站模板谁,也不知道厨师的炒菜方式与步骤 请求者可以要求修改命令执行时间,例如晚1小时再要二、实现
命令模式由三种角色构成:
发布者 invoker(发出命令,调用命令对象,不知道如何执行与谁执行) 接收者 receiver (提供对应接口处理请求,不知道谁发起请求) 命令对象 command(接收命令,调用接收者对应接口处理发布者的请求)
实现代码如下:
class Receiver { // 接收者类 execute() { console.log(接收者执行请求); } } class Command { // 命令对象类 constructor(receiver) { this.receiver = receiver; } execute () { // 调用接收者对应接口执行 console.log(命令对象->接收者->对应接口执行); this.receiver.execute(); } } class Invoker { // 发布者类 constructor(command) { this.command = command; } invoke() { // 发布请求,调用命令对象 console.log(发布者发布请求); this.command.execute(); } } const warehouse = new Receiver(); // 厨师 const order = new Command(warehouse); // 订单 const client = new Invoker(order); // 请求者 client.invoke();三、应用场景
命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时,希望用一种松耦合的方式来设计程序,使的请求发送者和请求接收者能够消除彼此之间的耦合关系
菜单
现在我们需要实现一个界面,包含很多个按钮。每个按钮有不同的功能,我们利用命令模式来完成
<button id="button1"></button> <button id="button2"></button> <button id="button3"></button> <script> var button1 = document.getElementById("button1"); var button2 = document.getElementById("button2"); var button3 = document.getElementById("button3"); </script>然后定义一个setCommand函数,负责将按钮安装命令,可以确定的香港云服务器是,点击按钮会执行某个 command 命令,执行命令的动作被约定为调用 command 对象的 execute() 方法。如下:
var button1 = document.getElementById(button1) var setCommand = function(button, conmmand) { button.onclick = function() { conmmand.execute() } }点击按钮之后具体行为包括刷新菜单界面、增加子菜单和删除子菜单等,这几个功能被分布在 MenuBar 和 SubMenu 这两个对象中:
var MenuBar = { refresh: function() { console.log(刷新菜单目录) } } var SubMenu = { add: function() { console.log(增加子菜单) }, del: function(){ console.log(删除子菜单); } }这些功能需要封装在对应的命令类中:
// 刷新菜单目录命令类 class RefreshMenuBarCommand { constructor(receiver) { this.receiver = receiver; } execute() { this.receiver.refresh(); } } // 增加子菜单命令类 class AddSubMenuCommand { constructor(receiver) { this.receiver = receiver; } execute() { this.receiver.refresh(); } } // 删除子菜单命令类 class DelSubMenuCommand { constructor(receiver) { this.receiver = receiver; } execute() { this.receiver.refresh(); } }最后就是把命令接收者传入到 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);撤销
命令模式的作用不仅是封装运算块,而且可以很方便地给命令对象增加撤销操作
页面中有一个 input 文本框和一个 button 按钮,文本框中可以输入一些数字,表示小球移动后的水平位置,小球在用户点击按钮后立刻开始移动,如下:
<div id="ball" style="position: absolute; background: #000; width: 50px; height: 50px" ></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>换成命令模式如下:
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(); };撤销操作的实现一般是给命令对象增加一个名为 unexecude 或者 undo的方法,在该方法里执行 execute 的反向操作
在 command.execute 方法让小球开始真正运动之前,需要先记录小球的当前位置,在 unexecude 或者 undo 操作中,再让小球回到刚刚记录下的位置,代码如下:
class MoveCommand { constructor(receiver, pos) { this.receiver = receiver; this.pos = pos; this.oldPos = null; } execute() { this.receiver.start(left, this.pos, 1000, strongEaseOut); this.oldPos = this.receiver.dom.getBoundingClientRect()[this.receiver.propertyName]; // 记录小球开始移动前的位置 } undo() { 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方法中让小球会到刚刚记录的原始位置就可以
参考文献
https://www.runoob.com/design-pattern/command-pattern.html
https://juejin.cn/post/6844903673697402888
https://juejin.cn/post/6995474681813811208
很赞哦!(3982)
相关文章
- 旧域名的外链是否会对新建站点产生影响?
- 可持续数据中心运营的节能设计策略
- 构建边缘数据中心
- 面试官再跟你说中国没有根服务器,雪人计划让他了解下
- 顶级域名可以增加企业品牌的价值。随着经济的快速发展,域名已不再是企业在网络中的独立地位。顶级域名的服务范围、企业产品、综合形象体现等,对于企业单位来说,顶级域名的重要性不言而喻。
- 数据中心虚拟化的八个好处
- 数据中心管理技巧
- 实现量子计算产业化,量旋科技邀您一起见证量子计算的新未来
- 其次,一般域名注册有一个获取密码的按钮,域名注册商点击后会向您发送密码。在得到域名注册商发送的密码后,将其传输到域名服务提供商网站,然后输入密码,此时域名呈现申请状态。提交申请后,原注册人通常会向您发送一封电子邮件,询问您是否同意转让。此时,您只需点击同意转移按钮,域名注册商就可以成功转移。
- AI和HPC推动对更高密度的数据中心、新的即服务产品的需求
站长推荐
其次,一般域名注册有一个获取密码的按钮,域名注册商点击后会向您发送密码。在得到域名注册商发送的密码后,将其传输到域名服务提供商网站,然后输入密码,此时域名呈现申请状态。提交申请后,原注册人通常会向您发送一封电子邮件,询问您是否同意转让。此时,您只需点击同意转移按钮,域名注册商就可以成功转移。
IMT-2020(5G)推进组携手产业链发布裸眼3D产业推进倡议,加速裸眼3D移动应用规模化发展
HAS 2023:跃升数字生产力,加速迈向制造行业数字化转型新时代——华为制造军团解读业务战略方向
CXO思享会走进联想 20余家行业头部企业共议智能化新增长
5、企业注册国内域名需要证件,其它情况一律不需要证件。
保护服务器机房物理安全的五种优秀实践
如何使用Rust构建基本的HTTP Web Server?
数据架构中的数据问题