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

use*_*581 2 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';
}
Run Code Online (Sandbox Code Playgroud)

给出输出: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';
}
Run Code Online (Sandbox Code Playgroud)

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

为什么会这样呢?

Sto*_*ica 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);}
}; 
Run Code Online (Sandbox Code Playgroud)

这将允许在中进行覆盖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); } 
};
Run Code Online (Sandbox Code Playgroud)

现代编译器会抱怨您试图覆盖未声明为虚函数的功能。该错误将是显而易见的。