继承与组合 - 特定案例

时间:2018-02-08 21:02:53

标签: oop inheritance composition software-design

我一直在阅读关于继承与构图的内容。我知道在这个网站上已经有关于这个主题的分配,但我对这个具体的例子有疑问,我希望不会被视为重复。

到目前为止我收集了一些指导原则:

  • 首选组合而不是继承。
  • 因此,关系几乎总是意味着构成。
  • 是一种关系CAN意味着继承是最好的,但并非总是如此。


现在为示例

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

  • 包含可呈现图像的Image类。
  • Transform类就是定位。
  • Sprite类包含可以在特定位置呈现的图像。

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


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

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

  • 如果Sprite 从Transform继承,我不需要做任何事情,sprite-> setPosition()会自动为sprite对象调用Transform :: setPosition()。 / p>

  • 如果Sprite HAS 一个转换,我必须将所有这些方法重定向到Transform! (到目前为止,我一直在这样做,看起来效果很好) 我不想为每种定位方法写这样的东西:(已经有很多)

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

这似乎违反惯例。 你们都在想什么?

1 个答案:

答案 0 :(得分:0)

当你说“更容易”时,我认为你的意思是“更快”,因为让我们面对它,将调用从Sprite转发到Transform组件并不困难,它只需要更多打字(而且“更少打字”是很好,但我会先评估其他事情。选择继承优于作文的问题现在不存在,但可能会在以后出现。

使用公共继承,您只需要声明继承,并且Transrite中的所有公共接口都可以在Sprite中使用。所有。如果有一天你向Transform添加了一个“Rotate”方法,但是不希望Sprite以颠倒的方式显示,那么你必须以某种方式隐藏基类方法。 Matthieu和CodeFirst有很好的答案here关于如何隐藏在C ++中。但正如Matthieu指出的那样,通过隐藏你违反Liskov替换原则的方法。如果您使用过合成,那么您可能只是在Sprite的公共界面中忽略了“旋转”方法。

对于私有继承,你会更好一点,因为它代表了“在Sprite和Transform之间的关系中实现”,更接近现实,而不是公共继承所代表的“是一种”关系。但是你需要使用“using”语句来提供Transrite in Sprite中的方法(参见上一个链接中的Eugen答案)。所以你最终仍然需要编写额外的代码来实现你的目的(虽然少于组合)。

通过合成,我觉得你有更容易的选择来处理设计问题。你想简单地调用组件方法吗?你转发了电话。你想禁止组件方法吗?您不要将它添加到Sprite界面。是否要为一个方法添加功能(例如,将变换比例设置为不允许Sprite Image的大小太小的值)?您可以将方法添加到接口,但在调用Transform组件之前/之后执行一些额外的处理/检查...

如果您能够获得Scott Meyers的Effective C ++书籍,那么您有两个值得阅读的项目:“明智地使用私有继承”和“模型”具有“a”或“已实现” -terms-of“through composition”。从那里提取的最后一点有利于组合:“组合和私有继承都意味着实现了 - 但是组合更容易理解,所以你应该在任何时候使用它”

相关问题