【问题标题】:inheritance vs composition - specific case继承与组合 - 具体案例
【发布时间】:2018-02-08 21:02:53
【问题描述】:

我一直在阅读有关继承与组合的文章。我知道这个网站上已经有关于这个主题的文章,但是我对这个具体的例子有疑问,我希望不会被视为重复。

到目前为止我收集的一些指导方针:

  • 更喜欢组合而不是继承。
  • 因此,有关系几乎总是意味着组合。
  • Is-a 关系可能意味着继承是最好的,但并非总是如此。


现在举个例子

我一直在开发一个简单的游戏引擎来练习 C++。为此,我做了一些课程:

  • 包含可渲染图像的 Image 类。
  • Transform 类都是关于定位的。
  • Sprite 类包含一个可以在特定位置渲染的图像。

当然还有更多,但让我们保持简单的例子。


所以 - Sprite HAS 图像和 HAS 位置(变换)。遵循这意味着两者的组合的指导方针。但我认为让 Sprite 从 Transform 继承要容易得多。

因为我要做什么 sprite->setPosition() 和 sprite->setScale()。

  • 如果一个Sprite继承自Transform,我什么都不用做,sprite->setPosition()会自动为sprite对象调用Transform::setPosition()。 p>

  • 如果 Sprite 一个变换,我将不得不将所有这些类型的方法重定向到变换! (这就是我迄今为止一直在做的事情,它似乎工作正常) 我不想为每个定位方法都写这样的东西:(已经有不少了)

    Sprite::setPosition(Vector2 position) {
        mTransform.setPosition(Vector2 position);
    }
    

但是这似乎违背了惯例。 大家觉得呢?

【问题讨论】:

  • 你不能做一个成员函数来返回对转换的引用吗?这样您就不需要手动转接呼叫了。
  • 或者使用接口(纯虚类)来暴露Is-a,并用组合来实现。您将接口上的调用转发到实现成员对象。想要改变行为使用不同的组合对象。

标签: oop inheritance composition software-design


【解决方案1】:

当您说“更容易”时,我认为您的意思是“更快”,因为让我们面对现实吧,将调用从 Sprite 转发到 Transform 组件一点也不难,只是需要更多的输入(而“更少的输入”是很好,但我会先权衡其他事情)。选择继承而不是组合的问题现在不可能存在,但以后可能会出现。

使用公共继承,您只需要声明继承,Transform 的所有公共接口都可以在 Sprite 中使用。全部。如果有一天你在 Transform 中添加了一个“Rotate”方法,但不想让 Sprite 倒置显示,那么你必须以某种方式隐藏基类方法。 Matthieu 和 CodeFirst 提供了很好的答案here,关于如何在 C++ 中隐藏。但是正如马蒂厄所指出的那样,通过隐藏该方法,您违反了里氏替换原则。如果您使用过合成,您可能会忽略 Sprite 的公共接口中的“旋转”方法。

使用私有继承会更好一些,因为它代表了 Sprite 和 Transform 之间的“被实现”关系,比公共继承所代表的“是”关系更接近现实。但是随后您将需要放置“使用”语句以在 Sprite 中使用 Transform 中的方法(参见上一个链接中的 Eugen 回答)。所以你最终仍然需要编写额外的代码来实现你的目的(虽然比组合少)。

我觉得使用组合可以更轻松地处理设计问题。你想简单地调用组件方法吗?你转接电话。要禁止组件方法吗?您不会将其添加到 Sprite 界面。您是否想为一种方法添加功能(例如,保持变换比例不会设置为 Sprite 图像尺寸太小的值)?您将方法添加到接口,但在调用 Transform 组件之前/之后做一些额外的处理/检查...

如果您可以阅读 Scott Meyers 的 Effective C++ 一书,那么您有两点值得在本次讨论中阅读:“明智地使用私有继承”和“模型 'has-a' 或 'is-implemented-in -条款'通过组合“。从那里提取的支持组合的最后一点:“组合和私有继承都意味着在术语中实现,但是组合更容易理解,所以你应该尽可能地使用它”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 2014-01-17
    • 2015-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多