何时使用继承比较合适?

3
我一直得到非常直接的回答,如“如果要创建的子类是父类的一个子类型,请使用继承。”这在我做小项目时有效,但当我开始开发2D游戏引擎时,我遇到了冲突的情况。
假设我有一个基类GameObject,它有50个函数和5个成员变量,为了方便起见。这些函数包括设置器、获取器、动画函数、渲染、移动等等。对于我的玩家和敌人来说,这是一个完美的基类。
但我还有像道具和装备之类的对象,只需要(而且我只想能够访问)从GameObject继承的10个函数。我的物品仍然可以被定义为GameObject,但它不会移动或有任何动画。
在这种情况下该怎么办?我应该继承并忽略多余的函数,从而创建浪费内存的情况吗?我应该重写那10个函数,浪费时间吗?我应该将GameObject作为Item和Prop的私有成员变量,再次浪费内存,但允许我阻止访问任何不需要的函数吗?还是我应该从GameObject中删除所需的10个函数,并将它们放在一个单独的头文件中,创建一个辅助函数库?
编辑:
感谢回复。几乎所有人都建议将GameObject类分成更好定义的基类或使用组合。

1
忽略函数只有在它们是虚拟的时候才会浪费内存。 如果它们是虚拟的,那么只会浪费非常少的内存。 - Brian Bi
如果你的一些游戏对象不移动或不动画,那么将这些功能放在“GameObject”中并不是一个好的设计。 - Drew Dormann
您可以创建一个PropObject类,它扩展了GameObject,重写了应该忽略的10个函数以抛出异常,然后从任何“道具对象”中扩展PropObject - newfurniturey
2
Liskov替换原则 - Joseph Mansfield
我曾经有一个变态的想法,使用CRTP + 名称隐藏的组合来实现你所需求的功能,但这只会使整体设计过于复杂...我们需要让事情变得更简单,而不是更复杂。 - Marco A.
4个回答

7

您希望更详细地分解功能

使游戏对象仅包含成为游戏对象的基本要素。在您的情况下,这可能是10个关键函数。 让物品、道具等直接扩展此功能。 另外再创建一个类,比如Character,它继承自GameObject,并具有其他40个敌人和玩家都使用的函数。然后让Player和Enemy从Character继承。


3
继承需要非常谨慎地使用,记住这个规则 - 永远优先选择组合而不是继承。这不仅可以简化您的代码,还可以使其更加灵活和易于单元测试。您的Game类不应作为Player类的基类,但它可以包含一个Player对象或他们的向量。
请记住,您必须分离它们的功能。Game类不应过多地了解Player类。它只应知道其公共接口。因此,这里就出现了接口的概念。与其包含一些Player对象,还不如包含一些IPlayer接口的向量。然后,类Player将实现IPlayer接口。这很方便,因为在未来,您可能想要引入新类型的玩家,在这种情况下,您无需修改Game类,也无需修改Player类,而是会有一个新的比如说SuperPlayer类,它再次实现IPlayer接口。
关于这个主题有大量在线文档可供参考。但至少有两个经验法则:1)尽可能使用接口;2)优先选择组合而不是继承。
希望这对您有所帮助。

0

你可能想考虑一些其他的东西,而不是直接继承。

你有没有研究过实体系统

它们通常是将对象分成你想要的精确部分的好方法(它们确实需要相当数量的继承,只是更加分散)。

例如,你可以不再使用严格的GameObject -> Entity -> GroundEntity -> PlayerEntity等层次结构,而改为:

PlayerEntity具有组件:grounded、moveable、health等。


0

一个类应该代表一种抽象概念,并且应该具有内聚性,这意味着它更专注于表示一种类型的实体或执行相同类型的操作。

GameObject听起来太抽象了,除非你的游戏中所有对象都可以被视为GameObject。如果它们可以被视为GameObject,则GameObject应该具有所有对象在游戏中所能做到的最基本功能。如果不行,就放弃这种抽象。

从你提到的内容来看,你想要从GameObject“继承”的操作实际上可能属于一个Utility类。Utility类将拥有静态方法,可供需要类似操作的任何其他类使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接