当前位置: 首页 > 科技观察

面试官:说说你对命令模式的理解?应用场景?

时间:2023-03-19 19:27:16 科技观察

本文转载自微信公众号《JS每日一问》,作者慧慧。转载本文请联系JS每日一问公众号。1、什么是命令模式?它是最简单和优雅的模式之一。命令方式中的命令是指执行一些特定事情的指令。该模式旨在将函数调用、请求和操作封装到单个对象中,请求以命令的形式包装在一个对象中并传递给调用对象。调用对象寻找可以处理命令的适当对象,并将命令传递给执行命令的相应对象。例如,在一家快餐店,用户向服务员点餐。服务员在单子上记录用户的需求:请求者下单:参数是菜名(我要什么菜),时间(什么时候要),需求封装后,我可以修改参数是否有任何变化。用餐的内容被封装成一个命令对象,命令对象就是填写的列表。用户不知道接受者(厨师)是谁,也不知道厨师的烹饪方法和步骤。请求者可以请求修改命令执行时间,比如一小时后和两小时后,命令模式的实现由三个角色组成:发布者调用者(发布命令,调用命令对象,不知道如何执行)以及由谁执行)receiverreceiver(提供相应的接口来处理请求,不知道是谁发起的请求)command对象command(接收命令,调用receiver的相应接口来处理publisher的请求)的实现代码如下:classReceiver{//Receiver类execute(){console.log('Receiver执行请求');}}classCommand{//命令对象类constructor(receiver){this.receiver=receiver;}execute(){//调用receiver对应接口执行console.log('命令对象->receiver->执行对应接口');this.receiver.execute();}}classInvoker{//Publisher类构造函数(command){this.command=command;}调用(){//发布请求,调用命令对象console.log('Publisherpublishrequest');this.command.execute();}}constwarehouse=newReceiver();//cookconsorder=newCommand(warehouse);//orderconstclient=newInvoker(order);//请求者client.invoke();3、命令模式在应用场景中最常见的应用场景是:有时候你需要向一些对象发送请求,但是你不知道请求的接收者是谁,也不知道请求的是什么操作是。至此,我希望将程序设计成松耦合的方式,让请求发送者和请求接收者可以消除彼此之间的耦合关系。现在我们需要实现一个包含许多按钮的界面。每个按钮都有不同的功能,我们使用命令方式来完成然后定义一个setCommand函数,负责安装按钮按钮,可以确定点击按钮会执行某个命令,执行命令的动作约定调用命令对象的execute()方法。如下:varbutton1=document.getElementById('button1')varsetCommand=function(button,conmmand){button.onclick=function(){conmmand.execute()}}点击按钮后,具体行为包括刷新菜单界面,添加子菜单和删除子菜单等。这些函数分布在MenuBar和SubMenu这两个对象中:varMenuBar={refresh:function(){console.log('刷新菜单目录')}}varSubMenu={add:function(){console.log('添加子菜单')},del:function(){console.log('删除子菜单');}}这些函数需要封装在对应的命令类中://刷新菜单目录命令类classRefreshMenuBarCommand{constructor(receiver){this.receiver=receiver;}execute(){this.receiver.refresh();}}//添加子菜单命令类classAddSubMenuCommand{constructor(receiver){this.receiver=receiver;}execute(){this.receiver.refresh();}}//'删除子菜单命令类classDelSubMenuCommand{constructor(receiver){this.receiver=receiver;}execute(){this.receiver.refresh();}}finally是将命令接收者传入命令对象,并在按钮上安装命令对象:;setCommand(button1,refreshMenuBarCommand);setCommand(button2,addSubMenuCommand);setCommand(button3,delSubMenuCommand);undocommand方式的作用不仅仅是封装操作块,还可以非常方便的给command对象添加undo操作。页面中有一个输入文本框和一个按钮按钮,可以在文本框中输入一些数字来表示小球移动后的水平位置。用户点击按钮后球立即开始移动,如下:

输入位置球移动后:开始移动改为命令模式如下:pos){this.receiver=receiver;this.pos=pos;};MoveCommand.prototype.execute=function(){this.receiver.start("left",this.pos,1000,"strongEaseOut");};varmoveCommand;moveBtn.onclick=function(){varanimate=newAnimate(ball);moveCommand=newMoveCommand(animate,pos.value);moveCommand.execute();};undo操作的实现一般是在command对象中添加一个名为unexecude或undo的方法,在执行中执行相反的操作这个方法在command.execute方法让小球开始移动之前,需要记录小球的当前位置。在未执行或撤消操作中,让小球回到刚刚记录的位置。代码如下:pos,1000,'strongEaseOut');这。oldPos=this.receiver.dom.getBoundingClientRect()[this.receiver.propertyName];//记录小球开始移动前的位置}undo(){this.receiver.start('left',this.oldPos,1000,'strongEaseOut');//返回小球移动前记录的位置}}varmoveCommand;moveBtn.onclick=function(){varanimate=newAnimate(ball);moveCommand=newMoveCommand(animate,pos.value);moveCommand.execute();};cancelBtn.onclick=function(){moveCommand.undo();//取消命令};现在撤销功能很容易通过命令方式实现。如果是调用普通方法实现,可能每次都需要手动记录小球的轨迹,以便恢复到之前的位置。命令模式下小球的原始位置在小球开始移动之前,已经保存为命令对象的一个??属性,所以只需要再提供一个undo方法,在undo方法中,让小球回到刚才记录的原位置,可以参考https://www.runoob.com/design-pattern/command-pattern.htmlhttps://juejin.cn/post/6844903673697402888https://juejin.cn/post/6995474681813811208