JavaScript设计模式:装饰器模式
模式概念
如何在不改变对象本身功能的基础上为其增加额外的新功能?装饰器模式(Decorator Pattern)就是为此设计的一种结构型设计模式,它允许在不修改原有对象的前提下,动态地为其增加新的功能。这种模式通过创建一个包装对象来包裹实际对象,从而在不修改其代码的情况下实现功能的扩展。
装饰器模式是继承的替代技术,它通过对象组合来取代继承,实现动态扩展对象功能。
模式结构
装饰器模式的核心组件包括:
- Component(抽象组件):定义了一个对象接口,可以动态地为这些对象添加职责。
- ConcreteComponent(具体组件):定义了抽象组件的具体实现,即被装饰的具体对象。
- Decorator(抽象装饰者):持有一个
Component
对象的引用,定义与Component
一致的接口。 - ConcreteDecorator(具体装饰者):实现
Decorator
的接口,并为对象增加新的功能。
代码实现
// 抽象组件
class Component {
operate() {
throw new Error('This method must be implemented by subclasses');
}
}
// 具体组件
class ConcreteComponent extends Component {
operate() {
return 'ConcreteComponent';
}
}
// 抽象装饰者
class Decorator extends Component {
constructor(component) {
super();
this._component = component;
}
operate() {
return this._component.operate();
}
}
// 具体装饰者A
class ConcreteDecoratorA extends Decorator {
operate() {
const result = this._component.operate();
return `${result} + ConcreteDecoratorA`;
}
}
// 具体装饰者B
class ConcreteDecoratorB extends Decorator {
operate() {
const result = this._component.operate();
return `${result} + ConcreteDecoratorB`;
}
}
// 使用示例
const component = new ConcreteComponent();
console.log(component.operate()); // 输出: ConcreteComponent
const decoratedComponentA = new ConcreteDecoratorA(component);
console.log(decoratedComponentA.operate()); // 输出: ConcreteComponent + ConcreteDecoratorA
const decoratedComponentAB = new ConcreteDecoratorB(decoratedComponentA);
console.log(decoratedComponentAB.operate()); // 输出: ConcreteComponent + ConcreteDecoratorA + ConcreteDecoratorB
使用函数的装饰器:
// 为函数添加前置函数
Function.prototype.before = function(beforeFn) {
const _this = this;
return function() {
beforeFn.apply(this, arguments);
return _this.apply(this, arguments);
};
};
// 为函数添加后置函数
Function.prototype.after = function(afterFn) {
const _this = this;
return function() {
const result = _this.apply(this, arguments);
afterFn.apply(this, arguments);
return result;
};
};
// 创建一个函数
function test() {
console.log("111111");
}
// 使用装饰器增加前置和后置函数
const testAll = test
.before(() => { console.log("000000"); })
.after(() => { console.log("222222"); });
testAll();
// 输出:
// 000000
// 111111
// 222222
模式效果
优点:
- 动态扩展:不修改原有对象的代码即可动态地添加新功能。
- 透明性:装饰者和实际对象对客户端透明。
- 灵活性:可以叠加多个装饰者,灵活增加不同的功能。
缺点:
- 复杂性增加:使用多个装饰者可能会增加系统的复杂性。
- 难以管理:多个装饰者叠加时,追踪装饰的类变得困难。
模式应用
1. Axios 拦截器:
Axios 的拦截器是装饰器模式的一个典型应用。它允许在请求或响应前后对其进行拦截,修改或添加额外的处理逻辑。
// 创建 Axios 实例
const axios = axios.create({ baseURL: 'http://aaa.com' });
// 请求拦截器
axios.interceptors.request.use(
config => {
config.headers.Authorization = `Bearer ${token}`;
return config;
},
error => Promise.reject(error)
);
// 响应拦截器
axios.interceptors.response.use(
response => response,
error => Promise.reject(error)
);
axios.get('/user')
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
2. React 高阶组件(HOC):
高阶组件(Higher-Order Component, HOC)是 React 中的一种常见模式,它接受一个组件作为输入,返回一个增强了该组件的新组件。
class Home extends React.PureComponent {
render() {
return <div>{this.props.name}</div>;
}
}
// 定义高阶组件
function enhanceComponent(WrappedComponent) {
return class NewComponent extends React.PureComponent {
render() {
return <WrappedComponent {...this.props} />;
}
};
}
const EnhancedHome = enhanceComponent(Home);
3. TypeScript 装饰器:
TypeScript 提供了装饰器来增强类和类成员的功能。装饰器可以用于类、方法、属性和参数。
function methodWatcher(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with arguments:`, args);
return originalMethod.apply(this, args);
};
}
class MyClass {
@methodWatcher
myMethod(arg1: string, arg2: number) {
console.log('Original method logic');
}
}
const obj = new MyClass();
obj.myMethod('hello', 42);
4. Nest.js 中的装饰器:
Nest.js 是一个基于 Node.js 的服务器框架,它通过装饰器实现依赖注入、路由处理等功能,是装饰器模式的优秀应用。
总结
装饰器模式是一种强大且灵活的设计模式,它允许动态地为对象添加功能,而不会影响对象本身的结构。无论是在 HTTP 请求拦截、组件增强还是函数扩展方面,装饰器模式都提供了优雅的解决方案。