一、基础介绍
装饰者模式 UML 类图在不改变原对象的基础上,给对象动态增加职责(功能:属性或方法)的方式称为装饰者模式。
二、装饰函数
2.1 通过保存原引用的方式
如果需要绑定 onload 事件,但又不确定是否别人已经绑定过,为了避免覆盖掉之前的 window.onload 函数中的行为,常见的做法是:
var _onload = window.onload || function() {};
window.onload = function() {
_onload();
// do otherthing
}
缺点:
- 需要维护 _onload 这个中间变量
如果函数的装饰链较长,或者需要装饰的函数变多,这些中间变量的数量会越来越多。 - this 被劫持
当调用一个全局函数时,this 是指向 window 的,但是保存的原引用所指向的函数内部可能对于 this 的指向有特定的要求。(例如:document.getElementId
)
2.2 用 AOP 装饰函数
Function.prototype.before = function (beforefn) {
var _self = this; // 保存原函数的引用
return function () {
beforefn.apply(this, arguments); // 执行新函数,且保证 this 不被劫持
_self.apply(this, arguments);
}
}
Function.prototype.after = function(afterfn) {
var _self = this;
return function () {
var ret = _self.apply(this, arguments);
afterfn.apply(this, arguments);
return ret;
}
}
如果不喜欢上面污染原型的方式,可采用下面的方式:
function before(fn, beforefn) {
return function () {
beforefn.apply(this, arguments);
return fn.apply(this, arguments);
}
}
function after(fn, afterfn) {
return function () {
var ret = fn.apply(this, arguments);
afterfn.apply(this, arguments);
return ret;
}
}
2.3 ES7 Decorator
推荐阅读 阮一峰: 装饰器
三、装饰者模式和代理模式的区别
相同点:
- 不改变原有接口
- 这两种模式都描述了怎样为对象提供一定程度上的间接引用。
不同点:
代理模式的目的:当直接访问本体不方便或者不符合需要时,为本体提供一个替代者,控制对本体的访问。
代理模式强调 Proxy 与它的实体之间的关系。
代理模式通常只有一层代理-本体的引用。
装饰者模式的目的:为对象动态加入行为。
装饰者模式经常会形成一条长长的装饰链。
装饰者模式和适配器模式的区别
相同点: 不改变原有接口。
适配器的目的在于解决两个接口不兼容。
参考
《JavaScript 设计模式与开发实践》曾探
《JavaScript 设计模式》张容铭
Javascript设计模式系统讲解与应用
网友评论