求助:如何用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
相关产品推荐
相关产品推荐

