设计模式之装饰器模式

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是装饰器的类型定义

它是一个函数,使用时会接收到valuecontext两个参数

  • 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 适用场景

  • 在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为
  • 用继承来扩展对象行为的方案难以实现或者根本不可行

5. 参考资料

[1] 装饰设计(装饰者模式 / 装饰器模式) (refactoringguru.cn)

[2] TypeScript 装饰器 | 阮一峰 TypeScript 教程 (p6p.net)

posted @ 2023-11-30 00:34  当时明月在曾照彩云归  阅读(11)  评论(0编辑  收藏  举报