跳到主要内容

装饰

装饰模式解决什么问题?​

  • 问题: 需要在运行时给某个对象动态添加额外行为, 又不想为每种组合派生一个子类;
  • 解法: 让装饰器实现 Component 接口并持有一个 Component, 在转发前后附加行为;
  • 收益: 可以层层嵌套装饰器, 按需组合出行为组合;

装饰模式包含哪些角色?​

  • Component: 定义统一接口;
  • ConcreteComponent: Component 的具体实现, 提供基础行为;
  • Decorator: 持有 Component 属性并实现 Component 全部接口, 在转发时修改结果;
  • ConcreteDecorator: Decorator 的具体实现, 每层只负责一项附加行为;

装饰

如何用 TypeScript 实现装饰模式?​

interface Coffee {
getCost(): number;
getDescription(): string;
}

class SimpleCoffee implements Coffee {
getCost() {
return 10;
}
getDescription() {
return "Simple coffee";
}
}

// Decorator: 实现同一接口并持有被装饰对象
class MilkCoffee implements Coffee {
constructor(protected coffee: Coffee) {}

getCost() {
return this.coffee.getCost() + 2;
}
getDescription() {
return `${this.coffee.getDescription()} milk`;
}
}

class WhipCoffee implements Coffee {
constructor(protected coffee: Coffee) {}

getCost() {
return this.coffee.getCost() + 3;
}
getDescription() {
return `${this.coffee.getDescription()} whip`;
}
}

如何使用装饰模式?​

let coffee: Coffee = new SimpleCoffee();
coffee.getCost(); // 10; "Simple coffee"

coffee = new MilkCoffee(coffee);
coffee.getCost(); // 12; "Simple coffee milk"

coffee = new WhipCoffee(coffee);
coffee.getCost(); // 15; "Simple coffee milk whip"
  • 顺序: 装饰顺序决定叠加顺序, 调用方只需面向 Component 接口;
  • 相关: 装饰与静态代理结构相同, 区别在意图, 见 代理;