设计模式?如何做"Abstract generator creating abstract instance"

Design pattern? How to do "Abstract generator creating abstract instance"

本文关键字:creating abstract instance generator Abstract 何做 设计模式      更新时间:2023-10-16

我有两个类层次结构:配置模板和配置实例。配置模板可以生成配置实例。示例:从一组可能的配置创建笔。稍后我可能想添加铅笔和记号笔,因此层次结构。

(注意:在下面的 C++11 代码中,我跳过了明显的包含、虚拟析构函数、"使用命名空间 std"等;示例和问题是关于抽象的)

struct cConfigTemplate_WritingTool
{
    int length_range[2];
    string possible_shapes[] = {"circle", "octagon"};
};
struct cConfigInstance_WritingTool
{
    int length;
    string shape;
};
struct cConfigTemplate_Pen : public cConfigTemplate_WritingTool
{
    string ink_colours[] = {"red", "blue"};
    float chance_to_be_ball_point;
};
struct cConfigInstance_Pen : public cConfigInstance_WritingTool
{
    string ink_colour;
    bool is_ball_point;
};

我的问题是:

  • 这是一个好的设计吗?我需要层次结构来添加共享参数的其他配置类型。
  • 如果这是一个糟糕的设计,你会如何做得更好?有没有我错过的设计模式?如果是,它如何应用?
  • 如何实现以抽象方式从cConfigTemplate_WritingTool生成cConfigInstance_WritingTool的功能?例如

    cConfigTemplate_WritingTool * tool_template = new cConfigTemplate_Pen(); cConfigInstance_WritingTool * tool_instance = tool_template->generate_instance();

这是一个好的设计吗?

是的,这是一个很好的设计,还不错,但是,可以做一些改进。我更喜欢使用"类"而不是"结构"。

以前:

struct cConfigTemplate_WritingTool
{
  int length_range[2];
  string possible_shapes = {"circle", "octagon"};
};

后:

public class cConfigTemplate_WritingTool
{
  public int length_range[2];
  public string possible_shapes = {"circle", "octagon"};
};

使用"类"时,需要添加"public"关键字。

另一个一般建议是使用更有意义的标识符。

以前:

struct cConfigTemplate_WritingTool
{
  int length_range[2];
  string possible_shapes = {"circle", "octagon"};
};
struct cConfigInstance_WritingTool
{
  public int length;
  public string shape;
};

后:

struct TemplateClass
{
  int length_range[2];
  string possible_shapes = {"circle", "octagon"};
};
struct ToolClass
{
  int length;
  string shape;
};

Altought,这不是一个要求,使用更有意义的标识符,有助于描述您脑海中的问题,进入现实世界,程序/源代码。


如果这是一个糟糕的设计,你会如何做得更好?

也许你太早急于抽象超级类,并试图在当时做整个程序。

在设计层次结构时,您可能希望以相反的方式开始。首先设计没有"超"类的"叶"或"子"类,然后设计"超"类。

下面的代码示例不是完全C++程序。为了明确答案,省略了一些代码。


[1] 你想设计一个写作工具应用程序。

请注意,添加包装整个程序的"Universe"或"Application"对象是很常见的。

public /* concrete */ class WritingToolClass
{
  public:
    void Write() { ... }
} // class WritingToolClass
int main()
{
   WritingToolClass MyWritingTool = new WritingToolClass();
   MyWritingTool->Write();
   free MyWritingTool();
} // int main(...)

[2] 在此应用程序上,用户将使用几个具有预定义功能的工具。工具是对象,因此具有类定义。工具的示例包括"笔"、"图形"、"画笔"等。

public /* concrete */ class WritingToolClass
{
  public:
    void Write() { ... }
} // class WritingToolClass
public /* concrete */ class PenClass
{
  public:
    void Write() { ... }
} // class PenClass
public /* concrete */ class BrushClass
{
  public:
    void Write() { ... }
} // class BrushClass
int main()
{
   WritingToolClass MyWritingTool = new WritingToolClass();
   MyWritingTool->Write();
   free MyWritingTool();
} // int main(...)

[3] 这些工具具有在创建时分配的属性。

...
public /* concrete*/ class PenClass
{
  protected:
    ColorType Color;
    int Width;
  public:
    /* constructor */ PenClass
      (ColorType AColor, int AWidth) 
        {
          this.Color = AColor;
          this.Width = AWidth;
        }
} // class PenClass
public /* concrete */ class BrushClass
{
  protected:
    ColorType Color;
  public:
    /* constructor */ PenClass
      (ColorType AColor) 
        {
          this.Color = AColor;
        }
} // class BrushClass
...

[4] 为了创建具有给定功能的工具,应用程序具有一些特殊对象,这些对象类似于"工具"的工厂。

让我们称它们为"模板"。 对于每类工具,您都需要一个特定的"模板"或"工厂"。

该模板将为您提供一个特定的工具,使用一个名为"generateInstance"的函数:

...
public /* concrete */ class PenClass
{
  // ...
} // class PenClass
public /* concrete */ class PenTemplateClass
{
  public:
    PenClass generateInstance() { ... }
} // class PenTemplateClass
public /* concrete */ class BrushClass
{
  // ...
} // class BrushClass
public /* concrete */ class BrushTemplateClass
{
  public:
    BrushClass generateInstance() { ... }
} // class BrushTemplateClass
...

检查每个模板的"生成实例"函数是否返回不同的类型。这将在以后改变。


[5] "工具"是独立的,不相关的,具体的(不是抽象的)类。在示例中,它有几个重复的成员,其中一些被省略了。让我们为它们添加一个抽象的超类。

...
public /* abstract */ class ToolClass
{
  /* replaceable */ virtual void Draw() { ... }
} // class ToolClass
public /* concrete */ class PenToolClass: public ToolClass
{
  /* replaced */ virtual void Draw() { ... }
} // class PenToolClass
public /* concrete */ class BrushToolClass: public ToolClass
{
  /* replaced */ virtual void Draw() { ... }
} // class BrushToolClass
public /* concrete */ class FontToolClass: public ToolClass
{
  /* replaced */ virtual void Draw() { ... }
} // class FontToolClass
...

检查PenClass是否重命名为PenToolClass,其他工具也是如此。

我们甚至添加了一个新的"FontToolClass"类。因此,我们现在有一个小的"工具"类层次结构。


[6] 同样适用于称为"模板"的"工具"工厂。让我们添加一个抽象类,其中包含由具体的"模板"继承的代码。

public /* abstract */ class ToolClass
{
  // ...
} // class ToolClass
public /* abstract */ class TemplateClass
{
  public:
    /* replaceable */ virtual ToolClass generateInstance() { ... }
} // class TemplateClass
public /* concrete */ class PenTemplateClass: public TemplateClass
{
  public:
    /* replaced */ virtual ToolClass generateInstance() { ... }
} // class PenTemplateClass
public /* concrete */ class BrushTemplateClass: public TemplateClass
{
  public:
    /* replaced */ virtual ToolClass generateInstance() { ... }
} // class BrushTemplateClass
public /* concrete */ class FontTemplateClass: public TemplateClass
{
  public:
    /* replaced */ virtual ToolClass generateInstance() { ... }
} // class FontTemplateClass

请注意,"模板"的基类现在有一个generateInstance函数,即 virtual ,并返回一个ToolClass

并且,具体"模板"类中被替换的generateInstance函数也返回抽象类型,但在现实世界中,它应该返回与"工具"类匹配的函数。

有没有我错过的设计模式?如果是,它如何应用?

注意:前面的示例称为"工厂"软件设计模式。


如何实现功能以生成 从cConfigTemplate_WritingTool cConfigInstance_WritingTool 抽象的方式?

[7] 首先,这是通过在"模板"基类中定义一个virtual("可替换")函数来完成的。

public /* abstract */ class TemplateClass
{
  public:
    /* replaceable */ virtual ToolClass generateInstance() = 0;
} // class TemplateClass

= 0表示此函数没有代码,旨在在子类中替换。


[8] 并在"模板"类的子类中替换一个新的"虚拟"函数。

public /* concrete */ class PenToolTemplateClass: public TemplateClass
{
  public:
    ColorType Color;
    int Width;
  public:
    /* replaced */ virtual ToolClass generateInstance()
    {
      PenClass Result = new PenClass(this.Color, this.Width);
      return Result;
    }
} // class PenToolTemplateClass
public /* concrete */ class BrushToolTemplateClass: public TemplateClass
{
  public:
    /* replaced */ virtual ToolClass generateInstance()
    {
      // ...
    }
} // class BrushToolTemplateClass
public /* concrete */ class FontToolTemplateClass: public TemplateClass
{
  public:
    /* replaced */ virtual ToolClass generateInstance()
    {
      // ...
    }
} // class FontToolTemplateClass
public /* concrete */ class WritingToolClass
{
  public:
    void Write()
    {
      PenTemplateClass MyPenTemplate = new PenTemplateClass();
      MyPenTemplate.Color = Blue;
      MyPenTemplate.Width = 1;
      PenToolClass MyBluePen = MyPenTemplate->generateInstance();
        MyBluePen.Write();
      free MyBluePen();
      MyPenTemplate.Color = Red;
      MyPenTemplate.Width = 2;
      PenToolClass MyRedPen = MyPenTemplate->generateInstance();
        MyRedPen.Write();
      free MyRedPen();
      MyBrushTemplate.Color = Green;
      BrushToolClass MyGreenBrush = MyPenTemplate->generateInstance();
        MyGreenBrush.Write();
      free MyGreenBrush();
      // and so on
      free MyPenTemplate();
    } // void Write(...)
} // class WritingToolClass
int main()
{
   WritingToolClass MyWritingTool = new WritingToolClass();
   MyWritingTool->Write();
   free MyWritingTool();
} // int main(...)

设计类层次结构并非易事。前面C++的例子并不完整,只是给出你的问题的大致理想。

干杯。