gpt4 book ai didi

design-patterns - 在这个例子中装饰器模式真的有必要吗?

转载 作者:行者123 更新时间:2023-12-04 07:16:08 24 4
gpt4 key购买 nike

这是问题陈述

一家餐厅有 4 个披萨基地:

全麦披萨
木火披萨
芝士披萨
薄皮披萨

有8种配料:

番茄、洋葱、奶酪、意大利辣香肠、辣椒、大蒜、芝士、土 bean

给定披萨底料和 0 个或多个配料,计算披萨的价格(假设每个底料和配料都配置了一些价格)。

我的伪代码解决方案是:

    public class Pizza {
public int getPrice(base, String... toppings){
PizzaBaseMap.get(base) + toppingsMap.sum(t -> toppingsMap.get(t))
}



Hashmap<String, int> PizzaBaseMap= {
whole_wheat : 1
wood_fire : 2
cheese_filled : 2
thin_crust : 4
}

Hashmap<String, int> toppingsMap = {
tomato : 1
onion : 2
cheese : 4
pepporoni : 5
capsicum : 2
garlic : 2
paneer : 4
potato : 4
}

//client Code

int Price = new Pizza().getPrice("whole_wheat", ["tomato", "cheese"])

我真的需要像 Headfirst 设计模式书在他们的示例中建议的那样使用装饰器吗?使用装饰器模式的解决方案看起来像这样:

    public interface iPizza
{
double cost();
}

//Decorator
public interface iToppingDecorator:iPizza
{
}

//Pizza types
class WholeWheatPizza:iPizza
{
public double cost()
{

}
}

class WoodFire : iPizza
{
public double cost()
{

}
}

class CheeseFilled : iPizza
{
public double cost()
{

}
}

class Thincrust : iPizza
{
public double cost()
{

}
}

//Toppings inheriting Decorator Interface

class CheeseTopping:iToppingDecorator
{
iPizza pizza;
public CheeseTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class TomatoTopping:iToppingDecorator
{
iPizza pizza;
public TomatoTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class OnionTopping:iToppingDecorator
{
iPizza pizza;
public OnionTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class PepporoniTopping:iToppingDecorator
{
iPizza pizza;
public PepporoniTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class CapsicumTopping:iToppingDecorator
{
iPizza pizza;
public CapsicumTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class PaneerTopping:iToppingDecorator
{
iPizza pizza;
public PaneerTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class GarlicTopping:iToppingDecorator
{
iPizza pizza;
public GarlicTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

class PotatoTopping:iToppingDecorator
{
iPizza pizza;
public PotatoTopping(iPizza pizzatype)
{
this.pizza = pizzatype;
}

public double cost()
{
return <price> + pizza.cost();
}
}

//client
static void Main()
{
iPizza pizza1 = new WholeWheatPizza();
pizza1 = new CheeseTopping(pizza1);

Console.WriteLine("Pizza 1 cost: "+pizza1.cost()+"INR");

iPizza pizza2 = new WoodFire();
pizza2 = new CheeseTopping(pizza2);
pizza2 = new TomatoTopping(pizza2);
Console.WriteLine("Pizza 2 cost: " + pizza2.cost() + "INR");

Console.ReadLine();

}

我只是觉得这完全是矫枉过正,我的代码与装饰器模式的解决方案一样可扩展。有什么想法吗?

最佳答案

是的,在这种情况下这可能有点过分了。然而,想象一下更大的应用程序,有更多的配料;或者价格调节因素更复杂;或者您正在构建一个可重用的库。

在这些情况下,装饰器模式有两个优点:

  1. 您可以独立地在代码库中添加和删除装饰器,因为每个装饰器的行为都完全包含在其类中。
  2. 可以根据每个装饰器自定义对象的装饰方式

例如,假设我们有一项特别优惠,任何带有凤尾鱼的披萨均可享受 20% 的折扣(不要吃凤尾鱼!)。对于 HashMap 来说,这是相当麻烦的:

foreach (var topping in toppings)
if (topping is Anchovies)
price := price * 0.8
else
price := price - toppingCosts[topping]

使用装饰器模式,我们只需添加一个新类即可:

class AnchoviesToppingDecorator : IPizzaToppingDecorator
{
private IPizza pizza;

public AnchoviesTopping(IPizza pizza)
{
this.pizza = pizza;
}

public double cost()
{
return this.pizza.Cost() * 0.8f;
}
}

当然,装饰器应用的顺序就变得很重要。如果需要的话,可以使用类型系统来强制执行。


您可以使用类型系统对装饰器强制执行顺序。假设所有顶级装饰者必须先于折扣装饰者。在我们的系统中,装饰器通过其构造函数接受其前任。通过更改构造函数类型,我们可以限制可以构建的装饰器。

interface IPizzaToppingDecorator : IPizzaDecorator
{

}

interface IPizzaDiscountDecorator : IPizzaDecorator
{

}

public class HalfPriceDecorator : IPizzaDiscountDecorator
{
private IPizzaToppingDecorator pizzaToppingDecorator;

public HalfPriceDecorator(IPizzaToppingDecorator pizzaToppingDecorator)
{
this.pizzaToppingDecorator = pizzaToppingDecorator;
}

public double Cost()
{
pizzaToppingDecorator.Cost() * 0.5;
}
}

请注意构造函数如何采用 IPizzaToppingDecorator 而不是 IPizzaDecorator。这确保了 HalfPriceDecorator 只能在 IPizzaToppingDecorator 之后应用。

任何其他都会引发编译时错误;我们喜欢编译时错误,因为只有我们才能看到它们!


在这种情况下,我认为 Head First 示例可以通过流畅的界面进行改进。

能写出这样的文章不是很好吗?

new WholeWheatPizza().WithTomatoTopping().WithCheeseTopping().WithPepporoniTopping();

这可以通过 extension methods 来实现:

public static IPizza WithCheeseTopping(this IPizza pizza)
{
return new CheeseToppingDecorator(pizza)
}

关于design-patterns - 在这个例子中装饰器模式真的有必要吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32382022/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com