设计模式之装饰器模式
1. 定义
在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)
2. 口语化举例
装饰,这个词在生活中很常见,比如说房间装饰
某一天,笔者觉得卧室不温馨,想要装饰改善一下
一方面,不希望大量改变原来的卧室布局,这个工作量太大了
另一方面,希望能在卧室添加一些智能设备,增加科技感
所以,最终决定添加几盏暖灯光和几个智能设备即可,简要装饰一下
在原有基础上不做大的改变,只是添加一些小装饰,这就是装饰器模式
(下面的描述会沿用这个上述这个场景)
3. 源码示例
装饰器模式在编译器、代码语言层面比较常见
比如TypeScript在5.0版本就支持装饰器语法
装饰器函数的类型定义如下:
type Decorator = (
value: DecoratedValue,
context: {
kind: string;
name: string | symbol;
addInitializer?(initializer: () => void): void;
static?: boolean;
private?: boolean;
access: {
get?(): unknown;
set?(value: unknown): void;
};
}
) => void | ReplacementValue;
上面代码中,Decorator
是装饰器的类型定义
它是一个函数,使用时会接收到value
和context
两个参数
value
:所装饰的对象context
:上下文对象,TypeScript 提供一个原生接口ClassMethodDecoratorContext
,描述这个对象
一个装饰器使用示例如下:
function Greeter(value, context) {
if (context.kind === "class") {
value.prototype.greet = function () {
console.log("你好");
};
}
}
@Greeter
class User {}
let u = new User();
u.greet(); // "你好"
上面示例中,类装饰器@Greeter
在类User
的原型对象上,添加了一个greet()
方法,实例就可以直接使用该方法
更多关于TypeScript装饰器的语法可以参考:TypeScript 装饰器 | 阮一峰 TypeScript 教程 (p6p.net)
4. 总结
4.1 设计优点
-
单一职责原则
装饰器的职责是明确的
-
无需创建新子类即可扩展对象,可以在运行时添加或删除对象
装饰器可以动态地将功能注入到对象中
-
可以用多个装饰封装对象来组合几种行为
4.2 适用场景
- 在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为
- 用继承来扩展对象行为的方案难以实现或者根本不可行