《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画图这种,撤销就是先清空画布,然后再把记录的命令依次执行,撤销那步除外。实现撤销要看具体情况。

总结

命令模式呢,就是通过一个对象来管理命令(需要执行的指令集合),通过这个对象,可以将原本复杂的对象间的交互变得简单起来。同时因为降低了耦合度,也有利于代码的维护。

 

posted @ 2016-12-12 17:55  出世Sunny  阅读(338)  评论(0编辑  收藏  举报