我对 OO 设计过程相当陌生,所以请耐心等待......

我有两个实体需要建模为类,将它们称为“父级”和“子级”(它与实际问题域足够接近)。一位父母将有一个或多个孩子 - 在此应用程序中,我对没有孩子的父母不感兴趣。

我的大脑要去吃午饭的地方是我需要能够从另一个中找到一个。在我的数据库中,我可以使用正常的外键关系来实现这一点,并且 SQL 基于集合的性质使得可以轻松找到给定父级的所有子级,或给定子级的父级。但作为对象...?

思考 父级应该携带子级的集合(列表,无论什么)。我还认为每个孩子都应该引用其父母。然而,引用的循环性质让我很头疼。

我是:

  • 在正确的轨道上?
  • 完全偏离基地吗?如果是这样,我应该采取什么不同的做法?

这几乎肯定会在 VB.NET 中实现,但距离削减代码还有很长的路要走。

8 个答案后编辑:

谢谢大家。很难只选择一个答案来接受。

为了澄清答案中提出的一些问题:

  • 父母和孩子是非常不同的实体 - 根本没有继承关系。我之所以选择我这样做的名字,是因为它们确实非常接近现实世界中的问题域,现在看到它是从OO角度来看的混乱来源。
  • 层次结构只是一个深度 - 孩子永远不会在申请中生孩子。

再次感谢。

有帮助吗?

解决方案

创建树结构时,循环引用很好并且绝对标准。例如,HTML 的文档对象模型 (DOM) 在每个对象上都有父属性和子属性。 节点 在 DOM 树中:

interface Node {
    // ...
    readonly attribute Node     parentNode;
    readonly attribute NodeList childNodes;
    // ...
}

其他提示

听起来你在我看来是在正确的轨道上。根据您的域模型,父母有孩子,孩子有父母。您可能需要互相参考。

循环引用没有任何问题,您只需小心处理它们即可。当您从数据库加载实体时,您会遇到麻烦的是在服务器端以自动方式管理实体。例如,您使用查询从数据库中获取 Child 对象。包括家长信息吗?包括父母的孩子吗?

像 Lightspeed 或 Microsoft Entity Framework 这样的 ORM 工具通常使用“延迟加载”指令来处理这个问题。他们首先会获取您需要的内容(因此,当您获取子级时,它只会获取子级属性和父级的 ID)。如果稍后取消引用 Parent,它会获取 Parent 属性并实例化 Parent 对象。如果稍后您访问它的 Children 集合,它就会获取相关的子信息并为该集合创建 Child 对象。但在您需要它们之前,它不会填充它。

我认为希望能够以这种方式遍历对象图是合理的。从你的帖子中很难知道你是否有合理的理由,但我不认为这些参考文献本身就证明是一个糟糕的设计。

我相信你走在正确的道路上。为什么引用的循环性质会让你头疼?您遇到的根本问题是什么? Parent 对其子代的引用,以及 Child 有对其父级的引用吗?

您是在谈论类层次结构,其中父类了解其子类吗?

您应该不惜一切代价避免这种情况。

默认情况下,子类知道父类的所有信息, 因为它是父类的实例. 。但是,要让父类了解其子类,就要求子类也了解所有其他子类。这会在该类的一个子级和所有其他子级之间创建一种依赖关系。这是一个无法维护的场景 将要 将来会出现问题——如果你甚至可以编译或运行它,但在许多语言中情况并非如此。

也就是说,在我看来,您并不是在尝试执行类层次结构,而是尝试执行集合层次结构,即一颗树。在这种情况下,是的,你走在正确的轨道上;这是一个常见的范例。父节点有子节点的集合,子节点有对父节点的引用。

事情是?他们是 都是同一个班级!这是一个非常简单的 C# 示例:

public class Node
{
  public readonly Node Parent; // null Parent indicates root node
  public readonly List<Node> Children = new List<Node>();
  public Node(Node parent)
  {
     Parent = parent;
  }
  public Node()
  {
     parent = null;
  }
  public void AddChild(Node node)
  {
     Children.Add(node);
  }
}

我有一种感觉,这就是你真正想要的。使用这种范例,您可以将 Node 子类化以用于您可能拥有的任何邪恶目的。

如果我理解 P 的对象包含代表子项的对象数组 P->c[] 。任何没有子节点的节点 P 都是叶子......每个 P 包含 P->P' (父级)。

您指定的解决方案(父级包含对子级的引用,反之亦然)消除了遍历树来获取给定子级和节点子级的祖先的需要。这实际上只是一棵树,您可以在其上执行各种链接以及遍历和枚举它的算法。这很好!

我建议阅读树木章节 计算机编程的艺术 出色而深入地了解树结构以及枚举亲子关系和子代的有效方法。

如果孩子们 必须 有一个父级我通常只需要子构造函数中的父类型实例。

在我看来,你正在走向糟糕的设计。你的架构永远不应该有循环引用。

您可能应该重新检查为什么您的孩子需要向父母提供参考,反之亦然。我倾向于拥有一群孩子的父母。然后,您可以向父对象添加功能以检查子对象是否是该实例的子对象。

对目标的更好解释可能也会更有帮助......

编辑

我又读了一点(并听了评论)……事实证明我完全错了。事实上,循环引用确实有其用处,只要您小心对待它们并且不要让它们失控。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top