【问题标题】:Is inheritance a good tool to design a builder/factory [closed]继承是设计建造者/工厂的好工具吗[关闭]
【发布时间】:2012-06-05 12:44:03
【问题描述】:

我有几个复杂的类,它们是使用从要创建的类继承的独立创建者类构建的。

一个例子可能是由无序数据构成的图表。

class Graph{
  //....
  public:
   void showData(); 
  protected: 
    std::vector<std::pair<int,int> > mConnectedData;

}

class GraphCreator:private Graph{
  public:
    //...
    void construct();
  private:
   std::map<double,int> mSomeHelperContainer;
   //...
}

对于构造,我需要许多辅助函数和辅助数据,我将它们放在另一个类 GraphCreator 中。由于许多与图形相关的函数也是必需的,而且我在任何情况下都需要图形的数据,所以我使用私有继承。 由于这绝不是著名的 is-a 关系,而且由于私有继承通常被认为是不良设计的暗示,我有一些疑问: 这是一个好主意和设计工厂的一种适当方式,还是有一些我没有想到的主要缺点? 设计这样一个工厂的更好方法是什么?

编辑:

感谢到目前为止的回答! 一些额外的信息,使当前使用的方法的原因更清楚。 我不能使用静态创建方法(Creator 中的状态变量太多)并且我有另一个约束: 我想在库中向其他人提供独立于创建者的图表(例如,连同从文件中读取的方法)。 那些不应该关心创造者。因此我也有点不确定朋友的使用情况,因为它在 Graph 类中添加了代码。

【问题讨论】:

  • 你说得对,这闻起来像糟糕的设计。如果您发布更多代码(使用继承的东西),我们可以建议替代方案。
  • 这里是构建器模式的一个很好的例子,以防它帮助en.wikipedia.org/wiki/Builder_pattern
  • 为 Graph 提供一个公共接口以始终如一地从外部构建它,而我们让 GraphCreator 来完成这项工作有什么不好?
  • @user331471:从头开始构建图表的信息在包含图表的库中不可用(代码太多,依赖项太多等)。为构建图形而提供的唯一接口是文件阅读器。

标签: c++ design-patterns factory builder


【解决方案1】:

这不是一个好方法(从任何有数据的东西继承很少是)。

传统的方法是:

  • 使GraphCreator 成为friendGraph
  • Graph 中将方法实现为static Build 方法(直接)

决定主要取决于你是否需要“工厂”是有状态的。 class 用于表示状态,这是方法无法做到的。

  • 因此,如果您需要状态,则需要 class 来存储它,因此 GraphCreator 是您的最佳选择。
  • 对于无状态方法,static 方法更轻量级。

如果您还没有决定,请选择最简单的(static 方法),看看能走多远 :)

【讨论】:

  • 感谢您的建议。我不能使用静态方法(Creator 中的状态变量太多)并且我有另一个限制:我想将 Graph 与库中的 fileReader 一起提供给其他人,而不必关心创建者。因此我也有点不确定朋友的使用情况。因为它在 Graph 类中添加了代码。从 Graph 继承不会对 Graph 类产生影响。
  • @Martin:朋友不是问题,因为您可以与前向声明的类成为朋友。所以人们会知道存在一个class GraphCreator;,它是Graph 的一个friend,但他们不会知道这个类是什么。
  • 很公平,确实如此!到目前为止,我很少使用friend,因为我曾经读到它引入了比继承更紧密的耦合。为什么在这种情况下你更喜欢朋友而不是继承?
  • @Martin:是的,但这可能是一个优势。当然,如果你只有两个课程GraphGraphCreator,那可能没什么优势;但是,要向GraphCreator 公开一些细节,您需要“污染”Graphprotected 部分,最终意外地将它们同时暴露给Graph 的所有派生类。使用friend,您需要付出紧密耦合GraphGraphCreator 的成本,作为交换,您可以获得对所有其他派生类更好的封装。
【解决方案2】:

我从here 采纳的经验法则是

尽可能使用组合,必要时使用私有继承。

“你必须”的一个具体例子是,当你继承的类有一些你必须实现的虚函数或纯虚函数才能使用你的私有基时:如果没有继承,你根本无法做到。

从您的描述中看不出使用继承是不可避免的;因此,我认为最好使用组合。

【讨论】:

  • 我认为这里甚至不需要组合:构建器 (GraphCreator) 创建 Graphs 但不需要聚合任何内容(如果我正确理解问题的话)。
  • @LucTouraille 我的理解是,在当前的设计中,构建器需要存储它当前运行的实例。当然可以使该实例在构建器外部,并在每次调用时将其传递给其他静态的辅助方法,但这将是更重要的重构。
猜你喜欢
  • 2022-01-19
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多