继承还是组合:依赖“is-a”和“has-a”?

新手上路,请多包涵

当我设计类并且必须在继承和组合之间进行选择时,我通常使用经验法则:如果关系是“is-a” - 使用继承,如果关系是“has-a” - 使用组合。

总是正确的吗?

谢谢你。

原文由 Igor 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 565
2 个回答

不——“是一个”并不总是导致继承。一个被广泛引用的例子是正方形和长方形之间的关系。正方形是长方形,但是设计从 Rectangle 类继承 Square 类的代码会很糟糕。

我的建议是使用 Liskov Substitution Principle 来增强您的“是/具有”启发式。要检查继承关系是否符合里氏替换原则,请询问基类的客户是否可以在不知道它在操作子类的情况下对子类进行操作。当然,必须保留子类的所有属性。

在正方形/矩形的例子中,我们必须要问,矩形的客户端是否可以在不知道它是正方形的情况下对正方形进行操作。客户必须知道的只是它是在一个矩形上操作的。下面的函数演示了一个假设设置矩形宽度保持高度不变的客户端。

 void g(Rectangle& r)
{
    r.SetWidth(5);
    r.SetHeight(4);
    assert(r.GetWidth() * r.GetHeight()) == 20);
}

这个假设适用于矩形,但不适用于正方形。所以函数不能在正方形上运行,因此继承关系违反了里氏替换原则。

其他示例

原文由 Sir Rippov the Maple 发布,翻译遵循 CC BY-SA 4.0 许可协议

是和不是。

这条线可以模糊。 OO 早期的一些非常糟糕的 OO 编程示例并没有帮助解决这个问题,例如:Manager is an Employee is an Person。

关于继承,您必须记住的是:继承破坏了封装。继承是一个实现细节。关于这个主题有各种各样的文章。

最简洁的总结方法是:

更喜欢作曲。

这并不意味着使用它来完全排除继承。它只是意味着继承是一个后备位置。

原文由 cletus 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题