命令模式的应用场景:
有时候向某些对象发送请求,但是不知道请求接收者和发送者是谁,也不知请求操作是什么,此时用一种松耦合的方式来设计程序,使得发送者和接收者能够消除耦合关系
面向对象形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <body> <button id="button1">点击按钮1</button> <script> let btn1 = document.getElementById('button1') let setCommand = function(button,command){ button.onclick = function(){ command.execute() } } let MenuBar = { refresh :function(){ console.log("刷新菜单目录") } } let RefreshMenuBarCommand = function(receiver){ this.receiver=receiver } RefreshMenuBarCommand.prototype.execute = function(){ this.receiver.refresh() } let refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar) setCommand(button1,refreshMenuBarCommand) </script> </body>
|
闭包形式
可以使用闭包的命令模式,将命令接收者封闭在闭包产生的环境中,执行命令的操作更简单,仅仅是执行回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| let btn1 = document.getElementById('button1') let setCommand = function(button,command){ button.onclick = function(){ command.execute() } } let MenuBar = { refresh :function(){ console.log("刷新菜单目录") } } let RefreshMenuBarCommand = function(receiver){ return function(){ return receiver.refresh() } } let refreshMenuBarCommand = new RefreshMenuBarCommand(MenuBar) setCommand(button1,refreshMenuBarCommand)
|
使用命令模式可以方便给对象增加撤销命令操作,撤销命令是执行命令的反向操作,文本编辑器的Ctrl+Z和围棋中的悔棋都是撤销命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <body> <div id="ball" style="position: absolute;background: #000;width:50px;height:50px"></div> <input type="text" id="pos"> <button id="moveBtn">开始移动</button> <button id="cancleBtn">撤销命令</button> <script> let ball = document.getElementById('ball') let pos = document.getElementById('pos') let moveBtn = document.getElementById('moveBtn') let cancleBtn = document.getElementById('cancleBtn') let moveCommand; let MoveCommand = function (receiver,pos) { this.receiver = receiver; this.pos = pos; this.oldPos=null } MoveCommand.prototype.excute = function(){ this.receiver.start('left',this.pos,1000,'strongEaseout') oldPos = this.receiver.dom.getBoundingClientRec()[this.receiver.propertyName] } MoveCommand.prototype.undo = function(){ this.receiver.start('left',this.oldPos,1000,'strongEaseout') } moveBtn.onclick=function(){ let animate = new Animate(ball) moveCommand = new MoveCommand(animate,pos.value) moveCommand.excute() } cancleBtn.onclick=function(){ moveCommand.undo() } </script> </body>
|
宏命令
是一组命令的集合,通过执行宏命令可以执行一批命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| let quitCommand = { execute: function(){ console.log('退出') } } let loginCommand ={ execute: function(){ console.log('登录') } } let MacroCommand = function(){ return { commandList:[], add: function(command){ this.commandList.push(command) }, execute:function(){ for(let i=0;command;command = this.commandList[i]){ command.execute() } } } } let macroCommand = new MacroCommand() macroCommand.add(quitCommand) macroCommand.add(loginCommand) macroCommand.execute()
|
总结
一般,命令模式都会在command命令对象中保存一个接收者负责真正执行客户的请求,这种命令模式是傻瓜式命令,它只负责把客户的命令转发给接收者执行,让请求发起者和接收者之间尽可能解耦
聪明式命令对象可以直接实现请求,不需要接收者的存在,形式上和策略模式很像,通过使用意图分辨它们,策略模式指向的问题域更小,所有策略目标一致,它们只是达到这个目标的不同手段,命令模式指向的问题域更广,command对象解决的目标更具发散性。