这是问题陈述
一家餐厅有4个比萨基地:
全麦披萨
木火比萨
奶酪填充披萨
薄皮披萨
有8个浇头:
番茄,洋葱,奶酪,Pepporoni,辣椒,大蒜,芝士,土豆,
计算比萨饼的价格给予比萨饼基础和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"])
Run Code Online (Sandbox Code Playgroud)
我是否真的需要使用装饰器,就像Headfirst desgin模式书在他们的例子中所暗示的那样?装饰器模式的解决方案如下所示:
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();
}
Run Code Online (Sandbox Code Playgroud)
我觉得这是一个完全矫枉过正,我的代码与装饰模式的解决方案一样可扩展.有什么想法吗?
是的,在这种情况下可能有点过头了.然而,想象一个更大的应用程序,有更多的浇头; 或者价格修饰者更复杂的地方; 或者您正在构建可重用的库.
在这些情况下,装饰器模式有两个优点:
例如,假设我们有一个特别优惠,任何披着凤尾鱼的披萨都是20%的折扣(不要吃凤尾鱼!).使用哈希映射这非常麻烦:
foreach (var topping in toppings)
if (topping is Anchovies)
price := price * 0.8
else
price := price - toppingCosts[topping]
Run Code Online (Sandbox Code Playgroud)
使用装饰器模式,我们可以添加一个新类:
class AnchoviesToppingDecorator : IPizzaToppingDecorator
{
private IPizza pizza;
public AnchoviesTopping(IPizza pizza)
{
this.pizza = pizza;
}
public double cost()
{
return this.pizza.Cost() * 0.8f;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,装饰器应用程序的顺序变得很重要.如有必要,可以使用类型系统强制执行此操作.
您可以使用类型系统强制装饰器上的订单.假设所有顶部装饰器必须在折扣装饰器之前.在我们的系统中,装饰器通过它们的构造函数接受它们的前任.通过更改构造函数类型,我们可以限制我们可以构建的装饰器.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
注意构造函数如何取一个IPizzaToppingDecorator而不是一个IPizzaDecorator.这确保了HalfPriceDecorator只能在a之后应用IPizzaToppingDecorator.
其他任何东西都会抛出编译时错误; 我们喜欢编译时错误,因为只有我们才能看到它们!
在这种情况下,我认为Head First示例可以通过流畅的界面进行改进.
能写这个不是很好吗?
new WholeWheatPizza().WithTomatoTopping().WithCheeseTopping().WithPepporoniTopping();
Run Code Online (Sandbox Code Playgroud)
这可以通过扩展方法实现:
public static IPizza WithCheeseTopping(this IPizza pizza)
{
return new CheeseToppingDecorator(pizza)
}
Run Code Online (Sandbox Code Playgroud)