一.概念
装饰器模式核心价值:
- 非侵入式扩展:无需修改核心功能源代码
- 责任链模式:通过装饰器链组合复杂逻辑
- 避免条件判断:消除冗余的if (featureX)代码膨胀
二.使用举例
- 原型扩展
<html>
<button tag="login" id="button">点击打开登录浮层</button>
<script>
Function.prototype.after = function (afterfn) {
var __self = this;
return function () {
var ret = __self.apply(this, arguments);
afterfn.apply(this, arguments);
return ret;
}
};
var showLogin = function () {
console.log('打开登录浮层');
}
var log = function () {
console.log('上报标签为: ' + this.getAttribute('tag'));
}
showLogin = showLogin.after(log); // 打开登录浮层之后上报数据
document.getElementById('button').onclick = showLogin;
</script>
</html>
- 工具函数扩展
<html>
<button tag="login" id="button">点击打开登录浮层</button>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 工具函数:创建函数执行后的增强函数
function composeAfter(original, afterFn) {
return function(...args) {
const result = original.apply(this, args);
afterFn.apply(this, args);
return result
};
}
// 原始函数:不包含副作用
const showLogin = () => {
console.log('打开登录浮层');
};
// 副作用函数:需要访问触发元素属性
const trackEvent = function() {
console.log('上报标签为: ' + this.getAttribute('tag'));
};
// 函数组合:合并核心逻辑与监视记录
const combinedFunction = composeAfter(showLogin, trackEvent);
// DOM 交互封装在闭包内
const button = document.getElementById('button');
button.addEventListener('click', combinedFunction);
});
</script>
</html>
三. 应用场景
- 日志记录
实现对函数调用的跟踪,不改动原函数逻辑
function logDecorator(func) {
return function (...args) {
console.log(`Calling ${func.name} with ${args}`);
const result = func.apply(this, args);
console.log(`Result: ${result}`);
return result;
};
}
// 使用装饰器
const add = logDecorator(function(a, b) {
return a + b;
});
add(2, 3); // 输出调用日志
- 性能分析
测量函数执行时间
function timerDecorator(func) {
return function (...args) {
const start = performance.now();
const result = func.apply(this, args);
console.log(`Time taken: ${performance.now() - start}ms`);
return result;
};
}
// 装饰计算密集型函数
const fibonacci = timerDecorator(function(n) {
return n <= 1 ? n : fibonacci(n-1) + fibonacci(n-2);
});
fibonacci(30); // 输出耗时
3.参数校验
确保函数参数符合规范
function validateParams(func) {
return function (...args) {
args.forEach(arg => {
if (typeof arg !== 'number') throw new Error('Invalid parameter type');
});
return func.apply(this, args);
};
}
const multiply = validateParams(function(a, b) {
return a * b;
});
multiply(2, 'three'); // 抛出参数类型错误
关键优势总结:
- 代码复用:将常用功能封装为装饰器库
- 高内聚性:避免将横切逻辑嵌入核心业务代码
- 可插拔性:通过装饰器叠加或替换灵活控制功能组合
- DRY原则:如权限验证逻辑只需维护一处
通过装饰器模式,开发者能更自然地实现"开闭原则":对扩展开放,对修改关闭。
四. 总结
通过装饰器模式,框架开发者能够:
- 保持核心功能的最小稳定
- 提供无限扩展可能性
- 减少因功能增加导致的维护成本指数级增长
这种将「必须功能」与「期望功能」分离的设计,在现代前端框架(如React Hooks)、中间件(如Koa)中得到了广泛采用,是构建可扩展系统的核心策略