第十五章装饰者模式

在程序开发时,我们不希望某个类或者函数的方法非常复杂,一次就包含很多职责;那么我们可以采用装饰者模式,它可以在不改变原生对象的基础上,动态地给某个对象添加一些额外的方法或者属性,使其满足更复杂的用户需求。

实现

一个例子,我们希望在原有的onload基础上添加一个方法,而我们不想改变原有的onload方法(或者方法太复杂,总之我们保持器神秘性),那么我们可以这么做:

    window.onload = funciton(){// 不知道的逻辑  ***}
    function my(){alert(2);} // 我自己的逻辑
    
    var _onload = window.onload || function(){};
    window.onload = funciton(){
        _onload();
        my();
    }

上面这样的做法有可能会产生一个问题,那就是作用域的不延续(也就是this被劫持的问题),比如:

    var _getElementById = document.getElementById;
    document.getElementById = function(id){
        alert(1);
        return _getElementById( id ); // 调用的时候会抛出异常,因为getElementById需要document作用域。
    }

为了解决这类问题,同时提出一个比较适用的装饰者解决方案,我们借组AOP进行实现:

  // 实现1  本文都采用此方法
Function.prototype.before = function( fn ){
    var _self = this;
    return function(){
        fn.apply(this, arguments); 
        _self.apply(this, arguments);
    }
}
    
Function.prototype.after = function( fn ){
    var _self = this;
    return function(){
        _self.apply(this, arguments);
        fn.apply(this, arguments); 
    }
}

// 实现2
Function.prototype._$aop = function(_before,_after){
    var f = function(){},
        _after = _after||f,
        _before = _before||f,
        _handler = this;
    return function(){
        var _event = {args:[].slice.call(arguments,0)};
        _before(_event);
        if (!_event.stopped){
            _event.value = _handler
                  .apply(this,_event.args);
            _after(_event);
        } 
        return _event.value;
    };
};

那么可以把上面的方法进行如下装饰:

    document.getElementById = document.getElementById.before(function(){
        alert(1);
    })
实用

几个用到AOP的地方:

  • 数据统计: 如果我们要统计事件,假设点击出现登录框时要发送统计请求,可以采用如下所示的方法:

      var showLogin = function(){
          // open the dialog
      }
      var log = function(){
          // 上报
      }
      showLogin = showLogin.after(log);
    
  • 改变函数参数: 当我们网站受到攻击时,需要在ajax请求中加上一个token参数,如下:

      // 原来的ajax
      var ajax = funciton( type, url, param ){// ajax逻辑}
          
      // 修改后的
      var ajax = function( type, url, param ){
          param = param || {};
          param.token = getToken();
          ajax(type, url, param);
          // ajax逻辑
      }
          
      // 如果我们又不想改变原来的ajax库(有可能以后新的项目需要用到,互联网总是很多的新项目..)
      ajax = ajax.before(function(type, url, param){
          param.token = getToken(); 
      });
    
  • 校验需求: 提交表单时,校验不通过,直接返回。

    Function.prototype.before = function( fn ){
       var _self = this;
       return function(){
         if (fn.apply(this, arguments) === false){
             return;
         } 
         _self.apply(this, arguments);
       }
     }
    
     function formSumbit(){
         // ajax提交
     }
     function validate(){
         if( user.name === ''){
             alert("名字为空");
            return false;
         }
         ...
     }
     formSumbit = formSumbit.before(validate);
    
装饰者模式和代理模式的区别

代理模式的目的是,当直接访问本体不方便或者不符合需求时,为这个本体提供一个代替者。本体定义了关键功能,而代理提供或拒绝对它的访问,或者在访问本体前做一些额外的事情。 换句话说,代理模式强调一种关系(Proxy与它的实体之间的关系),这种关系一开始就可以被确定。以图片加载为例,为图片设置src时最终目的,而在之前设置一个loading图片是一个聪明的做法。
装饰者模式是为对象动态的加入行为,用于不能确定本体对象全部功能的情况下,因此有可能形成一条长长的装饰链。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容