为什么装饰器模式实现需要具有核心类的公共抽象超类?

时间:2019-04-02 06:29:06

标签: c++ design-patterns decorator

我正在尝试c++中的装饰器设计模式。但是,如果没有抽象超类(核心和装饰类都从中继承),我将无法实现它。

我不明白为什么需要抽象超类。

我工作的装饰器示例:

#include <string>
#include <iostream>
using namespace std;

// abstract superclass
class Pizza
{
  public:
    virtual string GetDescription() = 0;
    virtual int GetCost() = 0;
};

// base class that can be extended
class Margharita: public Pizza 
{ 
   private:
    string description;
    int cost;
   public:
     Margharita(string t, int c){description = t; cost = c;} 
     string GetDescription(){return(description);}
     int GetCost(){return(cost);}
}; 

// decorator class that extends base class
class ExtraCheese: public Pizza
{
   private:
    Pizza* pizza;

   public:
    // constructor
    ExtraCheese(Pizza* p) {pizza = p;}

    string GetDescription() { return (pizza->GetDescription() + ", Extra Cheese"); } 
    int GetCost() {  return(pizza->GetCost() + 20); } 
};

int main()
{
  // create decorated object
  Pizza* pizza = new ExtraCheese(new Margharita("Margharita", 100));
  cout <<  pizza->GetDescription() << '\n';
  cout << pizza->GetCost() << '\n';
}

给出输出:Margharita, Extra Cheese 120

如果我删除抽象超类,装饰将停止工作:

#include <string>
#include <iostream>
using namespace std;

// base class that can be extended
class Pizza
{
  private:
   string description;
   int cost;
  public:
    Pizza(){description = "Pizza"; cost = 100;};
    string GetDescription(){return(description);}
    int GetCost(){return(cost);}
}; 

// decorator class that extends base class
class ExtraCheese: public Pizza
{
   private:
    Pizza* pizza;

   public:
    // constructor
    ExtraCheese(Pizza* p) {pizza = p;}

    string GetDescription() { return (pizza->GetDescription() + ", Extra Cheese"); } 
    int GetCost() {  return(pizza->GetCost() + 20); } 
};

int main()
{
  // create decorated object
  Pizza* pizza = new ExtraCheese(new Pizza());
  cout <<  pizza->GetDescription() << '\n';
  cout << pizza->GetCost() << '\n';
}

在这种情况下,输出仅显示核心对象(Pizza 100)的属性。

为什么会这样?

1 个答案:

答案 0 :(得分:5)

当删除抽象基类时,您使函数GetDescriptionGetCost不是虚拟的。因此,它们不会动态分配。这就是pizza->GetDescription()调用Pizza成员函数的原因,它是仅基于pizza静态类型解析的调用。

您无需具有抽象基础即可使其再次工作,只需动态分配即可,因此只需添加虚拟说明符

class Pizza
{
  private:
   string description;
   int cost;
  public:
    Pizza(){description = "Pizza"; cost = 100;};
    virtual string GetDescription(){return(description);}
    virtual  int GetCost(){return(cost);}
}; 

这将允许ExtraCheese中的优先级被动态调度拾取。您还可以通过使用override说明符来帮助编译器捕获此类错误。您是否像这样定义ExtraCheese

class ExtraCheese: public Pizza
{
   private:
    Pizza* pizza;

   public:
    // constructor
    ExtraCheese(Pizza* p) {pizza = p;}

    string GetDescription() override { return (pizza->GetDescription() + ", Extra Cheese"); } 
    int GetCost() override {  return(pizza->GetCost() + 20); } 
};

现代编译器会抱怨您试图覆盖未声明为虚函数的功能。错误会很明显。