定义
对于使用者是透明的,不知道是被装饰了
// 定义抽象组件接口
interface Component {
operation(): void;
}
// 定义具体组件类
class ConcreteComponent implements Component {
operation(): void {
console.log('执行具体组件的操作');
}
}
// 定义装饰器接口,它继承自组件接口
interface Decorator extends Component {
readonly component: Component;
}
// 定义装饰器抽象类
abstract class BaseDecorator implements Decorator {
readonly component: Component;
constructor(component: Component) {
this.component = component;
}
abstract operation(): void;
}
// 定义具体装饰器类A
class ConcreteDecoratorA extends BaseDecorator {
operation(): void {
this.component.operation(); // 调用被装饰对象的操作
this.addedFunctionality(); // 添加额外的功能
}
private addedFunctionality(): void {
console.log('执行具体装饰器A的额外功能');
}
}
// 定义具体装饰器类B(可选,展示不同的装饰方式)
class ConcreteDecoratorB extends BaseDecorator {
operation(): void {
this.addedFunctionality(); // 先添加额外的功能
this.component.operation(); // 再调用被装饰对象的操作
}
private addedFunctionality(): void {
console.log('执行具体装饰器B的额外功能');
}
}
// 使用示例
const component = new ConcreteComponent();
const decoratorA = new ConcreteDecoratorA(component);
const decoratorB = new ConcreteDecoratorB(decoratorA);
decoratorB.operation(); // 输出: 执行具体装饰器B的额外功能 -> 执行具体装饰器A的额外功能 -> 执行具体组件的操作
场景
装饰器模式在前端开发中的应用场景非常广泛,主要包括以下几个方面:
- UI组件的扩展:在Vue、React等现代前端框架中,装饰器模式可以用于在不修改组件原有结构的情况下,为组件添加额外的功能或样式。例如,可以通过装饰器组件来包装一个表单组件,为表单添加提交验证、错误提示等功能1。
- 事件处理的增强:对于需要处理复杂事件的UI组件,可以使用装饰器模式来添加或修改事件处理逻辑。例如,为按钮添加点击事件的日志记录、防抖或节流等功能2。
- 功能组合的灵活性:在需要根据不同条件为组件组合不同功能时,装饰器模式提供了极大的灵活性。通过组合不同的装饰器,可以轻松地实现不同的功能组合,而无需为每种组合创建新的组件23。
- 第三方库的增强:在使用第三方库时,有时需要为库中的某些方法或对象添加额外的功能,但又不想修改第三方库的源码。此时,可以使用装饰器模式来创建一个装饰器,通过拦截第三方库的方法调用来实现功能增强1。
- 数据请求的处理:在前端应用中,数据请求是一个常见的需求。可以使用装饰器模式来为数据请求添加额外的处理逻辑,如缓存、日志记录、请求重试等。通过组合不同的装饰器,可以构建出功能丰富的数据请求处理流程2。
- 性能优化:在某些情况下,可以使用装饰器模式来优化组件的性能。例如,通过装饰器为组件添加懒加载功能,以减少初始加载时的资源消耗1。
- 国际化与本地化:在开发需要支持多语言的前端应用时,可以使用装饰器模式来为组件添加国际化支持。通过装饰器来包装组件,并在其中处理语言切换的逻辑,可以方便地实现组件的国际化与本地化3(尽管这一应用场景可能更多地与策略模式或适配器模式相关,但装饰器模式同样可以作为一种解决方案)。
需要注意的是,在前端开发中应用装饰器模式时,应充分考虑其对组件树结构和性能的影响。过度使用装饰器可能会导致组件树变得复杂,并增加额外的渲染和计算开销。因此,在使用装饰器模式时,应根据实际需求进行权衡和选择。 案例
function decorate(phone) {
phone.fn2 = function () {
console.log("指环");
};
}
const phone = {
name: "iphone12",
fn1() {},
};
const newPhone = decorate(phone);
/**
* 增加前置执行的函数
*/
Function.prototype.beforeExec = function (fn) {
const _this = this;
return function wrapper() {
fn.apply(this, arguments);
return _this.apply(this, arguments);
};
};
/**
* 增加后置执行的函数
*/
Function.prototype.afterExec = function (fn) {
const _this = this;
return function wrapper() {
const response = _this.apply(this, arguments);
fn.apply(this, arguments);
return response;
};
};
优缺点
缺点:被多次装饰后,函数变多了,函数间联系变多了,调试和排查问题复杂了。