You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何用JavaScript ES6类语法正确实现装饰器模式?

用ES6类实现装饰器模式的完整指南

嘿,我来帮你把这个装饰器模式的实现补全并梳理清楚~你现在的思路是对的:用基础菜品类作为核心组件,用配菜类作为装饰器来动态扩展功能,但有几个小细节需要调整,我一步步给你说明:

首先修正核心问题

你的SideDish类里,getPrice()和getDes()调用super.getPrice()是不对的——因为super指向的是父类Dish,而Dish里的方法是空实现。装饰器模式的核心是委托给被包装的对象,所以应该调用this.dish对应的方法。

完整实现代码

// 基础组件:定义菜品的核心接口
class Dish {
  getPrice() {
    throw new Error("必须实现getPrice方法");
  }
  getDes() {
    throw new Error("必须实现getDes方法");
  }
}

// 具体组件:基础菜品(牛排)
class Steak extends Dish {
  getPrice() {
    return 13;
  }
  getDes() {
    return "Steak";
  }
}

// 抽象装饰器:所有配菜的父类,持有被装饰的菜品实例
class SideDish extends Dish {
  constructor(dish) {
    super();
    this.dish = dish; // 保存被装饰的菜品对象
  }

  // 委托给被装饰对象的方法,子类可以重写来扩展
  getPrice() {
    return this.dish.getPrice();
  }

  getDes() {
    return this.dish.getDes();
  }
}

// 具体装饰器1:薯条
class Pommes extends SideDish {
  constructor(dish) {
    super(dish);
  }

  // 扩展价格:基础菜品价格 + 薯条价格
  getPrice() {
    return this.dish.getPrice() + 5;
  }

  // 扩展描述:基础菜品描述 + 薯条
  getDes() {
    return `${this.dish.getDes()} + Pommes`;
  }
}

// 具体装饰器2:酱汁(再给你加一个例子,展示多重装饰)
class Sauce extends SideDish {
  constructor(dish) {
    super(dish);
  }

  getPrice() {
    return this.dish.getPrice() + 2;
  }

  getDes() {
    return `${this.dish.getDes()} + Black Pepper Sauce`;
  }
}

// 测试使用
let myMeal = new Steak();
console.log(myMeal.getDes()); // 输出: Steak
console.log(myMeal.getPrice()); // 输出: 13

// 给牛排加薯条
myMeal = new Pommes(myMeal);
console.log(myMeal.getDes()); // 输出: Steak + Pommes
console.log(myMeal.getPrice()); // 输出: 18

// 再加黑椒汁
myMeal = new Sauce(myMeal);
console.log(myMeal.getDes()); // 输出: Steak + Pommes + Black Pepper Sauce
console.log(myMeal.getPrice()); // 输出: 20

关键要点解释

  • 基础组件(Dish):定义了所有菜品必须实现的方法,这里我把空方法改成抛出错误,强制子类必须实现接口,避免遗漏。
  • 具体组件(Steak):实现了基础的菜品功能,是我们要装饰的核心对象。
  • 抽象装饰器(SideDish):作为所有装饰器的父类,它持有一个被装饰的Dish实例,并且默认委托所有方法给这个实例。这样子类装饰器只需要重写需要扩展的方法即可,不用重复实现所有逻辑。
  • 具体装饰器(Pommes、Sauce):继承自SideDish,重写getPrice()和getDes()方法,在原菜品的基础上添加自己的价格和描述,实现动态扩展。

这种方式的好处是:你可以自由组合不同的装饰器,给基础菜品添加任意多的附加功能,不需要修改基础类的代码,完全符合开闭原则。

内容的提问来源于stack exchange,提问作者Mikelgo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:22:27