0%

JavaScript设计模式--命令模式

刚看到命令模式的时候,感觉这不就是通常写代码的方式吗,单独算作一种模式有什么意义呢?寥寥几行的代码就可以实现的东西为什么要搞这么复杂?
诚然,设计模式起源于强类型的语言,对JavaScript这种动态语言来说,函数可以作为参数四处传递并在任意位置灵活的进行调用,似乎无需显式地构造一个用于命令模式调用的对象,但是,语言内置的命令模式和软件开发过程中的命令模式要解决问题其实是有所不同的,一种语言固然可以使得任何函数都可以被当作命令来调用,但是在团队开发中,我们应该尽可能地使得功能与功能之间的耦合减弱,并对调用接口做出统一的、辨识度高的规范,而设计模式正是一种可以作为团队内部进行高效沟通的桥梁,使得代码更加规范,可读性得到提高。

示例:小球动画轨迹的返回运动

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
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(); //撤销命令小球将执行返回运动
};

宏命令–下达一组命令

宏命令是指将一系列命令模式的命令集中在一条指令中,以达到同时下达多个命令操作的效果。通常的做法,是将命令模式下的命令放进队列(数组)中,并根据需求以恰当的方式一次执行,比如在命令中存在异步操作时,我们需要根据实际需要决定这些异步操作是以并发的形式发出还是以同步的形式逐次执行。
例:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
//以下为伪码
let commanda={
execute:function(){
fetch('...',{}).then(...)
}
},
commandb={
execute:function(){
fetch('...',{}).then(...)
}
}
//并发执行
let macroCommanda=function(){
let commandlist=[];
return {
add:function(command){
commandlist.push(command);
},
execute:function(){
commandlist.forEach(function(command){
command.execute();
})
}
}
}
let macroa=new macroCommanda();
macroa.add(commanda);
macroa.add(commandb);
macroa.execute();
//继发执行
let macroCommandb=function(){
let commandlist=[];
return {
add:function(command){
commandlist.push(command);
},
execute:async function(){
commandlist.forEach(function(command){
await command.execute();
})
}
}
}
let macrob=new macroCommandb();
macroa.add(commanda);
macroa.add(commandb);
macroa.execute();