2010-04-20 54 views
0

附加是一个经典的装饰模式。我的问题是你将如何修改下面的代码,以便你可以包装零或一个顶部的比萨Singleton模式与装饰器相结合

现在我可以有一个Pepporini - >香肠 - > Pepporini - >比萨类驾驶总成本高达10美元,为Pepporini收取两次费用。

我不认为我想要使用责任链模式,因为顺序无关紧要,并不是所有的浇头都被使用?

谢谢

namespace PizzaDecorator 
{ 
public interface IPizza 
{ 
    double CalculateCost(); 
} 

public class Pizza: IPizza 
{ 
    public Pizza() 
    { 
    } 

    public double CalculateCost() 
    { 
     return 8.00; 
    } 

} 

public abstract class Topping : IPizza 
{ 
    protected IPizza _pizzaItem; 

    public Topping(IPizza pizzaItem) 
    { 
     this._pizzaItem = pizzaItem; 
    } 

    public abstract double CalculateCost(); 

} 

public class Pepporini : Topping 
{ 
    public Pepporini(IPizza pizzaItem) 
     : base(pizzaItem) 
    { 
    } 

    public override double CalculateCost() 
    { 
     return this._pizzaItem.CalculateCost() + 0.50; 
    } 


} 

public class Sausage : Topping 
{ 
    public Sausage(IPizza pizzaItem) 
     : base(pizzaItem) 
    { 
    } 


    public override double CalculateCost() 
    { 
     return this._pizzaItem.CalculateCost() + 1.00; 
    } 
} 

public class Onions : Topping 
{ 
    public Onions(IPizza pizzaItem) 
     : base(pizzaItem) 
    { 
    } 

    public override double CalculateCost() 
    { 
     return this._pizzaItem.CalculateCost() + .25; 
    } 
} 
} 
+0

作业的任何机会? – womp 2010-04-20 20:56:50

+0

不,认为我隐瞒了“真实”的应用程序,为了我的工作,但这不仅仅是功课,而是实际上带来了金钱:) – Mike 2010-04-20 21:01:12

+0

当你开始思考模式时,这表明你过度使用它。 – 2010-04-20 21:08:46

回答

5

我会创建一个Topping类,它会有一个价格,并使你的Pizza类支持多种浇头。然后,根据每个添加的顶部来计算价格。

public interface IPizza 
{ 
    double CalculateCost(); 
} 

public class Pizza : IPizza 
{ 
    private List<Topping> toppings = new List<Topping>(); 
    private double stdCost; 

    public Pizza(double cost) 
    { 
     // this would be the standard cost of the pizza (before any toppings have been added) 
     stdCost = cost; 
    } 

    public Pizza(IList<Topping> toppings) 
    { 
     this.toppings.AddRange(toppings); 
    } 

    public void AddTopping(Topping topping) 
    { 
     this.toppings.Add(topping); 
    } 

    public void RemoveTopping(Topping topping) 
    { 
     this.toppings.Remove(topping); 
    } 

    public double CalculateCost() 
    { 
     var total = stdCost; 
     foreach (var t in toppings) 
     { 
      total += t.Price; 
     } 
    } 
} 

public class Topping 
{ 
    public Topping(string description, double price) 
    { 
     Description = description; 
     Price = price; 
    } 

    public double Price { get; private set; } 
    public string Description { get; private set; } 
} 

使用

IPizza p = new Pizza(5.00); 
p.AddTopping(new Topping("Pepperoni", 0.50)); 
p.AddTopping(new Topping("Sausage", 0.50)); 
var charge = p.CalculateCost(); // charge = 6.00 
+0

这就是我的建议。在比萨上下文中对我来说非常合乎逻辑。 – Robb 2010-04-20 21:17:01

+0

Mike说他“隐藏了*真实*应用程序”,所以他可能需要单独的,更复杂的逻辑来支持每个“顶部”而不仅仅是价格。 – 2010-04-20 21:21:49

+0

@BlueRaja:我认为迈克的意思是*隐藏了他所指的真实应用,而不是提供真实的代码示例。他正在使用Pizza/Topping关系。 – James 2010-04-20 21:26:23

1

我不会用装饰图案出现这种情况。相反,我会比萨持有一套ITopping:

public interface ITopping { 
    double cost(); 
} 

该集将保证没有重复。现在,要计算一个比萨的成本,你将它的基础价格加到所有浇头成本的总和上

+0

+1我会提出同样的建议,'Toppings'不是'IPizzas',应该用比萨饼来引用,而不是反过来。 (这可能只是由于Mike“隐藏了真正的应用程序”,在这种情况下,我们需要看到真正的类层次结构来帮助您进一步实现)。 – 2010-04-20 21:10:48

+0

“ITopping”的目的是什么?我真的不觉得需要上述设计来完成子类“Topping”。我认为一个包含价格/描述的简单的“Topping”类会很有用。 – James 2010-04-20 21:17:11