9. 装饰器模式(Decorator)

问题:想给对象动态添加功能,而不修改原有类或使用继承。

核心:用包装类包裹原对象,调用时先执行增强逻辑再委托给原对象。

class Coffee {
  cost() { return 10; }
  desc() { return '咖啡'; }
}

class MilkDecorator {
  #coffee;
  constructor(coffee) { this.#coffee = coffee; }
  cost() { return this.#coffee.cost() + 3; }
  desc() { return `${this.#coffee.desc()} + 牛奶`; }
}

class SugarDecorator {
  #coffee;
  constructor(coffee) { this.#coffee = coffee; }
  cost() { return this.#coffee.cost() + 1; }
  desc() { return `${this.#coffee.desc()} + 糖`; }
}

let myCoffee = new Coffee();
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);

console.log(myCoffee.desc()); // 咖啡 + 牛奶 + 糖
console.log(myCoffee.cost()); // 14
package decorator

import "fmt"

type Coffee interface {
  Cost() int
  Desc() string
}

type BaseCoffee struct{}

func (b BaseCoffee) Cost() int    { return 10 }
func (b BaseCoffee) Desc() string { return "咖啡" }

type MilkDecorator struct{ Coffee Coffee }

func (d MilkDecorator) Cost() int    { return d.Coffee.Cost() + 3 }
func (d MilkDecorator) Desc() string { return d.Coffee.Desc() + " + 牛奶" }

type SugarDecorator struct{ Coffee Coffee }

func (d SugarDecorator) Cost() int    { return d.Coffee.Cost() + 1 }
func (d SugarDecorator) Desc() string { return d.Coffee.Desc() + " + 糖" }

// 使用
// coffee := BaseCoffee{}
// coffee = MilkDecorator{Coffee: coffee}
// coffee = SugarDecorator{Coffee: coffee}
// fmt.Println(coffee.Desc()) // 咖啡 + 牛奶 + 糖
// fmt.Println(coffee.Cost()) // 14

JS 的高阶函数就是这个思路:fn = log(timing(fn)) 一层层包装。