【问题标题】:Is it bad form to refer to a derived type in a base type?在基类型中引用派生类型是不好的形式吗?
【发布时间】:2012-07-03 07:29:58
【问题描述】:

我有一个类别/文件树结构。类别和文件都可以有父级,所以我从具有 Parent 属性的公共基类派生它们。由于所有父节点显然总是类别(文件不能是父节点),因此将节点的 Parent 属性设置为 CategoryNode 类型似乎是有意义的。

基类引用派生类是不是不好的形式?如果是这样,为什么?如果是这样,有什么更好的方法来构建它?

class Node {
    public CategoryNode Parent {get; set;}
}

class File : Node {
    ...
}

class CategoryNode : Node {
    ...
}

【问题讨论】:

  • AFAIU,它们都扩展了相同的基类来共享属性,所以为什么不使用对自身具有递归引用的单个类呢?用额外的属性来区分它们。
  • 是的,这很糟糕。导致循环依赖。 Base 不应该对 Derived 有任何了解。
  • @Furqan,File节点不需要CategoryNode拥有的额外东西,比如children,所以我认为它不应该从CategoryNode派生。

标签: c# oop inheritance


【解决方案1】:

你可以...

interface IParent {
    ...
}

class Node {
    public IParent Parent {get; set;}
}

class File : Node {
    ...
}

class CategoryNode : Node, IParent {
    ...
}

这样,您不需要在基类中引用派生对象,此外,您可以更灵活地实际成为父对象,以防您稍后获得其他对象类型.此外,任何仅与父级相关的功能都可以在该接口中声明。

【讨论】:

  • 也许你可以在界面中添加:IEnumerable<IParent> ChildNodes?
  • @Steve 这是一个设计问题。当然这是可能的,但我不会再调用接口IParent。 OP 想要引用父对象,而不是子对象的(列表)。对我来说,将类似的东西声明为IEnumerable<IParent> Children 看起来很奇怪,而且我个人会将界面重命名为更合适的东西......如果你有一个包含许多这种命名风格示例的大型项目,你就是在通往地狱的路上恕我直言......
【解决方案2】:

如果属性Parent实际上是所有后代的公共属性并且总是种类CategoryNode,那不是问题。从语义上讲它是正确的,从技术上讲,只要您留在同一个库中,我认为它也是正确的(以避免循环引用)。

当您编写这样的代码时,这可能是一个问题:

// BAD CODE
if(myProp is subclassA) 
{ ... 
} 
else if (myProp is syubclassB) 
{ ...
}

这段代码很糟糕,因为你失去了继承的优势。

即使在 .Net Framework 中也有这样的结构。我想到的第一个例子是XObject.Parent 属性。

XElement 继承 XObject,XObject 发布一个 XElement 类型的属性。和你的 sn-p 一样。

【讨论】:

    【解决方案3】:

    基类不应该知道谁派生自它。

    如果你有这样的情况,你可能不想继承。您应该只使用某种形式的耦合。

    File 和 CategoryNode 在您的情况下应该包含一个 Node 成员。

    【讨论】:

    • 我不能同意你的看法。如果 Parent 总是一个 CategoryNode 呢?在基类中可能会出现问题,例如if(myProp is subclassA) { ... } else if (myProper is syubclassB) { ...}。这样的东西很脏。但不是 OP 建议的样本
    • 但事实并非如此。我们刚刚看到父级可以是 File,它与 CategoryNode 没有任何关联。
    • OP 说files can't be a parent
    【解决方案4】:

    其他选项是更改类层次结构以使 CategoryNode 成为根类 (a),或将属性类型更改为 Node (b)。

    这两种可能性都不好: (a) 文件将具有 CategoryNode 不需要的所有功能。 (b) 它将隐藏对象类型(始终为 CategoryNode)。这可能会导致代码中其他地方的无效转换错误。例如,如果您忘记了总有一个 CategoryNode 实例。

    考虑到这一点,我相信当前的代码是可以的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-08
      • 2018-07-31
      • 2020-06-01
      • 2011-04-23
      • 2014-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多