命令模式的命令指的是一个执行某些特定事情的指令;
6 命令模式
6.1 命令模式的用途
命令模式的命令指的是一个执行某些特定事情的指令;
命令模式的应用场景:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么。此时希望用一种松耦合的方式来设计程序,使得请求发图送者和请求接收者能够消除彼此之间的耦合关系;
6.2 命令模式的例子——菜单程序
实现一个点击不同按钮调用不同方法的功能 (模拟传统面向对象语言的命令模式实现):
按钮绘制:
1
2
3
4
5
6
7
8
9
10<body>
<button id="button1">点击按钮 1</button>
<button id="button2">点击按钮 2</button>
<button id="button3">点击按钮 3</button>
</body>
<script>
var button1 = document.getElementById( 'button1' ),
var button2 = document.getElementById( 'button2' ),
var button3 = document.getElementById( 'button3' );
</script>定义
setCommand函数,setCommand函数负责往按钮上面安装命令。约定点击按钮会执行某个command命令,执行命令的动作被约定为调用command对象的execute()方法;1
2
3var setCommand = function( button, command ){
button.onclick = function(){ command.execute(); }
};编写点击按钮之后的具体行为:
1
2
3
4
5
6
7var MenuBar = {
refresh: function(){ console.log( '刷新菜单目录' ); }
};
var SubMenu = {
add: function(){ console.log( '增加子菜单' ); },
del: function(){ console.log( '删除子菜单' ); }
};封装行为在命令类中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var RefreshMenuBarCommand = function( receiver ){
this.receiver = receiver;
};
RefreshMenuBarCommand.prototype.execute = function(){
this.receiver.refresh();
};
var AddSubMenuCommand = function( receiver ){
this.receiver = receiver;
};
AddSubMenuCommand.prototype.execute = function(){
this.receiver.add();
};
var DelSubMenuCommand = function( receiver ){ this.receiver = receiver; };
DelSubMenuCommand.prototype.execute = function(){ console.log( '删除子菜单' ); };把命令接收者传入到
command对象中,并且把command对象安装到button上面:1
2
3
4
5
6
7var refreshMenuBarCommand = new RefreshMenuBarCommand( MenuBar );
var addSubMenuCommand = new AddSubMenuCommand( SubMenu );
var delSubMenuCommand = new DelSubMenuCommand( SubMenu );
setCommand( button1, refreshMenuBarCommand );
setCommand( button2, addSubMenuCommand );
setCommand( button3, delSubMenuCommand );
6.3 JavaScript 中的命令模式
1 | var bindClick = function( button, func ){ button.onclick = func; }; |
JavaScript 作为将函数作为一等对象的语言,跟策略模式一样,命令模式也早已融入到了 JavaScript 语言之中;运算块不一定要封装在 command.execute 方法中,也可以封装在普通函数中。函数作为一等对象,本身就可以被四处传递。即使我们依然需要请求“接收者”,那也未必使用面向对象的方式,闭包可以完成同样的功能。
6.4 撤消命令
撤销操作的实现一般是给命令对象增加一个名为 unexecude 或者 undo 的方法,在该方法里执行 execute 的反向操作。在 command.execute 方法让小球开始真正运动之前,我们需要先记录小球的当前位置,在 unexecude 或者 undo 操作中,再让小球回到刚刚记录下的位置:
1 | var ball = document.getElementById( 'ball' ); |
5 宏命令
宏命令是一组命令的集合,通过执行宏命令的方式,可以一次执行一批命令。宏命令对象包含了一组具体的子命令对象,不管是宏命令对象,还是子命令对象,都有一个 execute 方法负责执行命令:
1 | var closeDoorCommand = { |
6 命令模式小结
JavaScript 可以用高阶函数非常方便地实现命令模式,命令模式在 JavaScript 语言中是一种隐形的模式。
系列链接
- JavaScript 设计模式基础知识
- JavaScript 设计模式(一)单例模式
- JavaScript 设计模式(二)策略模式
- JavaScript 设计模式(三)代理模式
- JavaScript 设计模式(四)迭代器模式
- JavaScript 设计模式(五)发布订阅模式
- JavaScript 设计模式(六)命令模式
- JavaScript 设计模式(七)组合模式
- JavaScript 设计模式(八)模板方法模式
- JavaScript 设计模式(九)享元模式
- JavaScript 设计模式(十)职责链模式
- JavaScript 设计模式(十一)中介者模式
- JavaScript 设计模式(十二)装饰者模式
- JavaScript 设计模式(十三)状态模式
- JavaScript 设计模式(十四)适配器模式
- JavaScript 设计模式(下)设计原则
- JavaScript 设计模式练习代码