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

    总结

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

  • 相关阅读:
    Nacos 1.3.0版本部署连接mysql 8+
    Java Certificate证书问题
    UIKit之浅析UIButton
    Xcode Coule not launch "aaa" press launch failed:timed out waiting for app launch
    Cocos2d-x 安装教程for mac(Xcode)
    关于继承UITableViewController若干问题
    Table的分割线偏移量设置 及其 UIEdgeInset详解
    retain、strong、weak、assign区别
    iOS 使用xib创建cell的两种初始化方式
    No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=x86_64, VALID_ARCHS=armv7 armv7s)
  • 原文地址:https://www.cnblogs.com/grey-zhou/p/6165427.html
Copyright © 2020-2023  润新知