我开了一家餐厅并创建了软件来确定菜单上所有项目的价格 我首先为每个菜单项创建一个类,以便可以使用界面计算价格。
interface HasPrice {
getPrice(): number;
}
class Ramen implements HasPrice {
getPrice() {
return 5;
}
}
class Spaghetti implements HasPrice {
getPrice() {
return 10;
}
}
然后她决定应该有顶部,所以她使用了装饰器模式。
class RamenWithPork extends Ramen {
getPrice() {
super.getPrice() + 3;
}
}
这种方法一直有效,直到我决定扩展顶部菜单,并且它变得太麻烦而无法处理组合数量的类。我应该如何修复它?
最佳答案
装饰器模式
好的,这就是 decorator design pattern 的工作- 您可以将您的对象包裹在另一个对象中,用额外的行为来装饰它们。这解决了复杂的依赖层次结构的问题。您已经经历过,但只是为了说明它 - 假设您已经经历过
class Rament {}
class RamenWithPork extends Ramen {}
class RamenWithChicken extends Ramen {}
class RamenWithMushrooms extends Ramen {}
如果您有RamenWithChickenAndMushroom
,会发生什么?您是否扩展了 RamenWithChicken
或 RamenWithMushrooms
还是只是 Ramen
?如果您有RamenWithPorkMushroomsAndChicken
怎么办?首先,你能记住这门课的名字吗?如果你一天后坐下来,你能记得它是 pig 肉、鸡肉和蘑菇还是 pig 肉、蘑菇和鸡肉吗?其次,如何在类层次结构中对其进行建模?
这就是装饰器模式的用武之地 - 您可以创建装饰器,例如:
interface OrderAddition {}
class WithChicken implements OrderAddition {}
class WithMushrooms implements OrderAddition {}
class WithPork implements OrderAddition {}
然后可以与任何食物一起使用。为了方便起见,这里添加了interface Extras
。它有助于保持依赖层次结构的重点和更实用 - HasPrice
有点太模糊 - 任何东西都可以有价格,但通过 OrderAddition
我们确切地知道它是什么类型。另一种调用它的方法是 OrderDecorator
- 它有点枯燥,但更具描述性,并且可以立即调用所使用的设计模式。
使用类
因此,使用装饰器后的代码如下所示:
interface MainDish { //renaming it to be more descriptive
getPrice(): number;
}
class Ramen implements MainDish {
getPrice() {
return 5;
}
}
class Spaghetti implements MainDish {
getPrice() {
return 10;
}
}
//decorators would need to do the same as the object they decorate,
//so the decorator implements the MainDish interface
interface OrderAddition extends MainDish {}
abstract class AbstractOrderAddition implements OrderAddition {
protected base: MainDish;
constructor(base: MainDish) {
this.base = base;
}
abstract getPrice(): number;
}
class WithChicken extends AbstractOrderAddition {
getPrice() {
return this.base.getPrice() + 5
}
}
class WithMushrooms extends AbstractOrderAddition {
getPrice() {
return this.base.getPrice() + 1
}
}
class WithPork extends AbstractOrderAddition {
getPrice() {
return this.base.getPrice() + 3
}
}
然后您可以执行以下操作:
let order: MainDish = new Ramen();
order = new WithPork(order);
order = new WithMushrooms(order);
Check on the TypeScript Playground
使用装饰器函数
然而,这是装饰器的高度正式的用法。在 JavaScript 中,您可以简化其中的一些内容,但仍然保持相同的想法。您可以将装饰器作为函数来修改给定的实例,而不是使用类:
interface OrderAdditionMaker{
(additionalPrice: number) : AddToOrder
}
interface AddToOrder {
(base: MainDish) : MainDish
}
const withChicken: AddToOrder = function withChicken(base: MainDish): MainDish {
//take a reference of the original
const originalGetPrice: MainDish["getPrice"] = base.getPrice.bind(base);
//overwrite the `getPrice` method
base.getPrice = function(): ReturnType<MainDish["getPrice"]> {
return originalGetPrice() + 5;
}
return base;
}
这可以通过使用 currying 进一步推广为更具功能性的路线。这样你就可以轻松导出所有装饰器函数:
//interface for making decorators
interface OrderAdditionMaker{
(additionalPrice: number) : AddToOrder
}
//decorator function
interface AddToOrder {
(base: MainDish) : MainDish
}
const withExtra: OrderAdditionMaker = function (additionalPrice: number) {
return function (base: MainDish): MainDish {
const originalGetPrice: MainDish["getPrice"] = base.getPrice.bind(base);
base.getPrice = function (): ReturnType<MainDish["getPrice"]> {
return originalGetPrice() + additionalPrice;
}
return base;
}
}
const withChicken: AddToOrder = withExtra(5);
const withMushrooms: AddToOrder = withExtra(1);
const withPork: AddToOrder = withExtra(3);
关于javascript - javascript类方法定义计算带配料的食品价格的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58377215/