Skip to content

概述

动态地将额外责任附加到对象上。对于扩展功能,装饰者提供子类化之外的弹性替代方案。 -- head first design patterns

![[decorator.excalidraw]]

和继承不同,它是对某种属性/方法在不影响原功能的情况下进行扩展

特性

  1. 在不修改目标代码的情况下,对目标功能进行扩展
  2. 遵循开放-关闭原则

![[note/reading/Head-First-Design-Patterns/设计模式 - 其他#开放关闭原则]]

什么时候情况下用

基于组合的方式去扩展功能时用到。比如在用 NestJS 时,里面会大量用到装饰器模式:

typescript

class A extends Controller {
  getA(
    @Res()
    res: Response,
    @Req()
    res: Request,
  ) {}
}

比如这个列子,A 类型的方法,我不关注参数的顺序是怎样,只要我使用某个装饰器定义某个参数,那它就是对应的类型值

实现

因为 @Decorator() 需要语法支持,所以下面的代码实现,来自于书中:

javascript
class Base {
  constructor(price) {
    this.price = price
  }

  cost() {
    return this.price
  }
}

class Decorator extends Base {
  target = null
}

class Milk extends Base {
}
class Coffee extends Decorator {
  constructor(price, _target) {
    super()
    this.target = _target
    this.price = price
  }

  cost() {
    return this.target.cost() + this.price
  }
}
class Mocha extends Decorator {
  constructor(price, _target) {
    super()
    this.target = _target
    this.price = price
  }

  cost() {
    return this.target.cost() + this.price
  }
}

const milk = new Milk(1)
const coffee = new Coffee(2, milk)
const mocha = new Mocha(3, coffee)

console.log('milk', milk.cost());
console.log('coffee', coffee.cost());
console.log('mocha', mocha.cost());
shell
# 输出
milk 1
coffee 3
mocha 6

总结

装饰器这种组合模式,我觉得非常好用,它的自由度很高,它的限制更多地是对某一类型的对象进行扩展,所以在特定领域/框架中使用装饰器的话,会更优于继承。