📜  装饰图案 |设置 1(背景)

📅  最后修改于: 2021-09-10 02:53:51             🧑  作者: Mango

为了理解装饰器模式,让我们考虑一个灵感来自“Head First Design Pattern”一书的场景。假设我们正在为一家比萨店构建一个应用程序,我们需要对他们的比萨类进行建模。假设他们提供四种类型的比萨,即 Peppy Paneer、Farmhouse、Margherita 和 Chicken Fiesta。最初我们只是使用继承并抽象出Pizza类中的通用功能。

披萨1

每个披萨都有不同的成本。我们已经覆盖了子类中的 getCost() 以找到合适的成本。现在假设一个新的需求,除了一个pizza,客户还可以要求几个配料,如Fresh Tomato、Paneer、Jalapeno、Capsicum、Barbeque等。让我们考虑一下,我们如何适应上述类的变化这样客户可以选择带配料的比萨饼,我们得到客户选择的比萨饼和配料的总成本。

让我们看看各种选择。

选项1
为每个披萨配料创建一个新子类。类图如下所示: 披萨2

这看起来非常复杂。课程太多了,这是一场维护噩梦。此外,如果我们想添加新的配料或披萨,我们必须添加很多类。这显然是非常糟糕的设计。

选项 2:
让我们向比萨基类添加实例变量来表示每个比萨是否有浇头。类图如下所示: 比萨3

超类的 getCost() 计算所有配料的成本,而子类中的 getCost() 计算特定比萨饼的成本。

// Sample getCost() in super class
public int getCost()
{
    int totalToppingsCost = 0;
    if (hasJalapeno() )
        totalToppingsCost += jalapenoCost;
    if (hasCapsicum() )
        totalToppingsCost += capsicumCost;

    // similarly for other toppings
    return totalToppingsCost;
}
// Sample getCost() in subclass
public int getCost()
{
    // 100 for Margherita and super.getCost()
    // for toppings.
    return super.getCost() + 100;
}

这种设计起初看起来不错,但让我们来看看与之相关的问题。

  • 浇头的价格变化将导致现有代码的更改。
  • 新的浇头将迫使我们添加新方法并更改超类中的 getCost() 方法。
  • 对于某些比萨饼,某些浇头可能不合适,但子类继承了它们。
  • 如果客户想要双辣椒或双芝士爆裂怎么办?

简而言之,我们的设计违反了最流行的设计原则之一——开闭原则,该原则规定类应该对扩展开放,对修改关闭。

在下一组中,我们将介绍装饰器模式并将其应用于上述问题。

参考资料: Head First Design Patterns(书籍)。