JavaScript 设计模式(中)——12. 装饰者模式

12 装饰者模式

装饰者模式定义为给对象动态地增加职责的方式;装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责;

12.1 装饰函数

在 JavaScript 中可以很方便地给某个对象扩展属性和方法,但却很难在不改动某个函数源代码的情况下,给该函数添加一些额外的功能通过保存原引用的方式就可以改写某个函数,如下:

window.onload = function(){ alert (1); }
var _onload = window.onload || function(){};
window.onload = function(){
  _onload();
  alert (2);
}

这样的代码符合开放-封闭原则的,在增加新功能的时候,确实没有修改原来的 window.onload 代码,但是这种方式存在以下两个问题:

  • 必须维护 _onload 这个中间变量,如果函数的装饰链较长,或者需要装饰的函数变多,这些中间变量的数量也会越来越多;
  • 其实还遇到了 this 被劫持的问题,遇到该问题时需要 用Function.prototype.apply() 手动设置 this 指向,如下document.getElementById 方法;
<html>
  <button id="button"></button>
  <script>
    var _getElementById = document.getElementById;
    document.getElementById = function(){
      alert (1);
      return _getElementById.apply( document, arguments );
    }
    var button = document.getElementById( 'button' );
  </script>
</html>

12.2 用 AOP (面向切面编程)装饰函数

  1. Function.prototype.before 方法和Function.prototype.after 方法实现:
Function.prototype.before = function( beforefn ){
  var __self = this; // 保存原函数的引用
  return function(){ // 返回包含了原函数和新函数的"代理"函数
    beforefn.apply( this, arguments ); // 执行新函数,且保证 this 不被劫持,新函数接受的参数
    // 也会被原封不动地传入原函数,新函数在原函数之前执行
    return __self.apply( this, arguments ); // 执行原函数并返回原函数的执行结果,
    // 并且保证 this 不被劫持
  }
}
Function.prototype.after = function( afterfn ){
  var __self = this;
  return function(){
    var ret = __self.apply( this, arguments );
    afterfn.apply( this, arguments );
    return ret;
  }
};

2.用 AOP 装饰函数修改上面例子:

<html>
  <button id="button"></button>
  <script>
  Function.prototype.before = function( beforefn ){
    var __self = this;
    return function(){
      beforefn.apply( this, arguments );
      return __self.apply( this, arguments );
    }
  }
  document.getElementById = document.getElementById.before(function(){ alert (1); });
  var button = document.getElementById( 'button' );
  console.log( button );
  </script>
</html>

12.3 AOP 的应用实例

12.4 装饰者模式和代理模式

代理模式和装饰者模式最重要的区别在于它们的意图和设计目的。

  • 代理模式:当直接访问本体不方便或者不符合需要时,为这个本体提供一个替代者,本体定义了关键功能,而代理提供或拒绝对它的访问,或者在访问本体之前做一些额外的事情;代理模式强调一种关系( Proxy 与它的实体之间的关系),这种关系可以静态的表达,在一开始就可以被确定;
  • 装饰者模式:为对象动态加入行为;装饰者模式用于一开始不能确定对象的全部功能时;代理模式通常只有一层代理-本体的引用,而装饰者模式经常会形成一条长长的装饰链;

12.5 装饰者模式小结

装饰函数是 JavaScript 中独特的装饰者模式,这种模式在实际开发中非常有用;同时在框架开发中也十分有用,通过装饰者模式为框架里的函数提供的一些稳定而方便移植的功能,这些个性化的功能可以在框架之外动态装饰上去,这样能避免为了让框架拥有更多的功能,而去使用一些 if、 else 语句预测用户的实际需要;

系列链接

  1. JavaScript 设计模式(上)——基础知识
  2. JavaScript 设计模式(中)——1.单例模式
  3. JavaScript 设计模式(中)——2.策略模式
  4. JavaScript 设计模式(中)——3.代理模式
  5. JavaScript 设计模式(中)——4.迭代器模式
  6. JavaScript 设计模式(中)——5.发布订阅模式
  7. JavaScript 设计模式(中)——6.命令模式
  8. JavaScript 设计模式(中)——7.组合模式
  9. JavaScript 设计模式(中)——8.模板方法模式
  10. JavaScript 设计模式(中)——9.享元模式
  11. JavaScript 设计模式(中)——10.职责链模式
  12. JavaScript 设计模式(中)——11. 中介者模式
  13. JavaScript 设计模式(中)——12. 装饰者模式
  14. JavaScript 设计模式(中)——13.状态模式
  15. JavaScript 设计模式(中)——14.适配器模式
  16. JavaScript 设计模式(下)——设计原则
  17. JavaScript 设计模式练习代码

本文主要参考了《JavaScript设计模式和开发实践》一书

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

推荐阅读更多精彩内容