《javascript设计模式与开发实践》阅读笔记(9)—— 命令模式
命令模式:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,此时希望用一种松耦合的方式来设计软件,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。
说法很复杂,简单来说就是希望真正做事情的对象不要直接被调用,当我们下达一些命令之后, 希望对象已经间接的执行了。这样做的好处是可以解耦,代码可以更为灵活,还可以管理命令,甚至完成命令队列这样的操作。
实现思路
为了实现这种效果,我们需要通过一个函数,创造一个接口对象,调用接口对象的方法,就是调用对象真正的方法。
下面的例子是常规的直接调用对象的方法
1 var bindClick = function( button, func ){ //两个参数一个是执行对象,一个是执行的函数
2 button.onclick = func;
3 };
4
5 var MenuBar = {
6 refresh: function(){
7 console.log( '刷新界面' );
8 }
9 };
10
11 bindClick( button1, MenuBar.refresh );
12
13 //不直接写button1.click=function(){} 是因为在改动频繁的开发中,改动起来很麻烦,毕竟谁触发什么事件都是不确定的。
现在我们使用命令模式创建一个接口对象
1 var setCommand = function( button, command ){ //command为接口对象
2 button.onclick = function(){
3 command.refresh(); //接口对象提供的方法
4 }
5 };
6
7 var MenuBar = {
8 refresh: function(){
9 console.log( '刷新菜单界面' );
10 }
11 };
12
13 var createCommand = function( obj ){ //创建接口对象的方法
14 return {
15 refresh: function(){
16 obj.refresh();
17 }
18 }
19 };
20
21 var menubar = createCommand( MenuBar ); //创建一个接口对象
22
23 /*也可以这么写 或者方法放到原型上
24 var createCommand( obj ){
25 this.obj=obj;
26 this.refresh=function(){
27 this.obj.refresh();
28 }
29 }
30
31 var menubar = new createCommand( MenuBar );
32
33 */
34
35 setCommand( button1, menubar ); //触发时调用接口对象的方法,接口对象再调用真正对象的方法。
从这里看好像和代理模式有点像,都是提供一个接口,内部做些处理再调用本体,但还是有区别的,代理模式的话代理对象只为一个本体服务,而命令模式中,接口对象就像一个黑盒子,可以依次执行命令,也能撤销命令,一个命令可能可以让不同的对象执行自己的方法,见下面的代码:
1 var list=(function(){ //接口对象,这里因为不存在通用的问题,所以直接写了
2 var arr=[];
3 return {
4 add:function(obj){
5 arr.push(obj);
6 },
7 execute:function(){
8 for(var i=0,l=arr.length;i<l;i++){
9 arr[i].execute();
10 }
11 }
12 }
13 })();
14
15 list.add( menubar );
16 list.add( headbar );
17 list.add( footbar );
18 list.execute();
上面这段代码就比较清晰了,命令的管理对象中的一个接口,可以执行不同对象的方法,等于导演说一句开机,剩下的人都可以自行其事。
这里我们假定对象都拥有一个execute方法,倘若对象没有一个公共的方法,那也可以给对象加一个,如果通过new的方式创建对象就在原型链上加,如果没有通过new,就直接添加
1 //new的方式
2 menubar=new Menubar();
3 Menubar.prototype.execute=function(){
4 this.refresh(); //真正需要执行的方法,下同
5 }
6 //直接加
7 menubar.execute=function(){
8 this.refresh();
9 }
撤销操作
撤销操作的实现一般是给命令对象增加一个名为unexecude或者undo的方法,在该方法里执行execute的反向操作。
比如动画,撤销时候回到一开始的位置,那就得记录一开始的位置,点撤销后回到那里;如果是canvas画图这种,撤销就是先清空画布,然后再把记录的命令依次执行,撤销那步除外。实现撤销要看具体情况。
总结
命令模式呢,就是通过一个对象来管理命令(需要执行的指令集合),通过这个对象,可以将原本复杂的对象间的交互变得简单起来。同时因为降低了耦合度,也有利于代码的维护。