概述
动态地将额外责任附加到对象上。对于扩展功能,装饰者提供子类化之外的弹性替代方案。 -- head first design patterns
![[decorator.excalidraw]]
和继承不同,它是对某种属性/方法在不影响原功能的情况下进行扩展
特性
- 在不修改目标代码的情况下,对目标功能进行扩展
- 遵循开放-关闭原则
![[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
总结
装饰器这种组合模式,我觉得非常好用,它的自由度很高,它的限制更多地是对某一类型的对象进行扩展,所以在特定领域/框架中使用装饰器的话,会更优于继承。