【问题标题】:Does the following indicate a bad design?以下是否表明设计不佳?
【发布时间】:2010-06-06 03:53:58
【问题描述】:

我想知道您是否认为以下代码通常表明设计不佳......

class X
{
public:
  ...
private:
  Y y;
};

Class Y
{
public:
   Y( X& value ){ x = value; };
private:
   X& x;
}

(即类 X 和 Y 之间存在某种循环依赖关系)。

【问题讨论】:

  • @Amardeep:你愿意详细说明一下吗?
  • x = value 需要在初始化列表中,否则无法编译。 :-)
  • @Oli:循环依赖是松散耦合的对立面。但当我更仔细地观察它并意识到它只是 Y 中 X 的引用时,它看起来不再那么糟糕了。
  • 您的代码无法编译。而 that 是糟糕的设计。这可能是一个小错误,但如果我们不知道您的代码实际上是什么样子,我们必须猜测我们的意思,然后我们无法确定我们的答案是否正确。

标签: c++ class dependencies


【解决方案1】:

取决于你想要做什么。某些设计(例如迭代器)需要此类循环。

【讨论】:

    【解决方案2】:

    不,我不认为这是糟糕的设计。它看起来像一个父子关系(这是一对一的),其中子节点有一个指向父节点的指针。

    这种设计的主要原因是如果有人可以在不通过X 的情况下获得对Y 的引用。如果对Y的所有访问都只能通过X完成,那么这样的引用就更值得怀疑了。

    正如 Billy ONeal 所指出的,一个例子可能是一个迭代器,它需要能够引用它所属的集合。这可以让一个迭代器进入一个不需要在调整数组大小时失效的数组,因为它会在每次访问时检查数组的当前缓冲区地址和当前大小。

    另一个例子是OrderLine 类(你的X),它包含对项目的引用和数量计数等。它还有一个DigitalLicense 类型的可选成员(你的Y)。 DigitalLicense 包含大量加密的许可证说明,因此它仅包含在与具有数字许可证的产品对应的OrderLines 中。

    在构造时,对DigitalLicense 的引用也会放在单独的映射中,并以许可证 ID 为关键字。现在可以根据地图中的许可证 ID 查找 DigitalLicense。然后使用反向引用从DigitalLicenseOrderLine。如果OrderLine 有类似的反向引用,则也可以返回到Order

    【讨论】:

    • 您能否详细说明其中的一些充分理由?我并不是说你错了,但我一直认为需要指向其“父”的指针的“子”是“代码味道”,但我总是愿意了解例外情况,这将是一个好的设计。
    • @Charles:这对于允许您遍历它们所属的树可能很有用。我相信std::map 是这样工作的。如果没有那个额外的父指针,递增迭代器将不会是所需的O(1) 操作。
    • @jalf:是的,我可以看到,对于本质上紧密耦合的对象,这可能是一个好主意。不过,我经常看到孩子们知道他们父母的类型(以及他们有父母的事实!),而更好的设计是让孩子不知道在哪里(或如何)拥有它,因此本质上更灵活并可在更多情况下重复使用。对于名为 XY 的类,这有点抽象。
    • @Charles:是的,同意了。
    【解决方案3】:

    在以前,例如在 VB6 中,这是一个糟糕的设计,因为 VB 无法删除两个对象,其中一个对象在另一个对象中被引用,反之亦然。由于C++没有引用计数,所以没有问题了。

    【讨论】:

      【解决方案4】:

      我不认为这是有问题的。事实上,这是一种相当常见的模式(即子对象维护对父对象的指针/引用)。

      【讨论】:

        【解决方案5】:

        这不一定是糟糕的设计,确实很常见。但是,在处理内存管理时,您确实需要非常小心这些设计。当每个类都像这样依赖另一个类时,您最终可能会遇到棘手的错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-01-19
          • 1970-01-01
          • 1970-01-01
          • 2010-12-15
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          相关资源
          最近更新 更多