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 (面向切面编程)装饰函数
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 语句预测用户的实际需要;
系列链接
- JavaScript 设计模式(上)——基础知识
- JavaScript 设计模式(中)——1.单例模式
- JavaScript 设计模式(中)——2.策略模式
- JavaScript 设计模式(中)——3.代理模式
- JavaScript 设计模式(中)——4.迭代器模式
- JavaScript 设计模式(中)——5.发布订阅模式
- JavaScript 设计模式(中)——6.命令模式
- JavaScript 设计模式(中)——7.组合模式
- JavaScript 设计模式(中)——8.模板方法模式
- JavaScript 设计模式(中)——9.享元模式
- JavaScript 设计模式(中)——10.职责链模式
- JavaScript 设计模式(中)——11. 中介者模式
- JavaScript 设计模式(中)——12. 装饰者模式
- JavaScript 设计模式(中)——13.状态模式
- JavaScript 设计模式(中)——14.适配器模式
- JavaScript 设计模式(下)——设计原则
- JavaScript 设计模式练习代码
本文主要参考了《JavaScript设计模式和开发实践》一书