0%

命令模式

命令模式的应用场景:

有时候向某些对象发送请求,但是不知道请求接收者和发送者是谁,也不知请求操作是什么,此时用一种松耦合的方式来设计程序,使得发送者和接收者能够消除耦合关系

面向对象形式:

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("刷新菜单目录")
}
}
//command对象
let RefreshMenuBarCommand = function(receiver){
this.receiver=receiver
}
RefreshMenuBarCommand.prototype.execute = function(){
this.receiver.refresh()
}
//命令接收者接传入到command对象,把command对象安装到button上
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("刷新菜单目录")
}
}
//command对象
let RefreshMenuBarCommand = function(receiver){
return function(){
return receiver.refresh()
}
}
//命令接收者传入到command对象,把command对象安装到button上
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对象解决的目标更具发散性。