如何处理类层次结构

How to handle class hierarchy

本文关键字:层次结构 处理 何处理      更新时间:2023-10-16

我有一个关于如何处理这种类型的类层次结构的问题。等级制度与游戏有关,但我认为这已经足够概括游戏开发了。我想这种事情偶尔会出现,所以我很好奇可能的解决方案

我有一个叫做baseccharacter的基类来定义游戏中的角色。它包含了所有的基本属性,状态,效果持有者,事件等等。我的大多数游戏逻辑都是在baseccharacter的实体上操作的,必要时进行强制转换。

从那里我继承到一个Humanoid类,它添加必要的结构和方法来添加设备(武器,盔甲等)的角色,然后最后我有一个playablecrole类,继承自Humanoid并添加像当前经验,可配置的能力结构等。

所以类结构很简单:

BaseCharacter——>人形——> PlayableCharacter

这种结构对于定义玩家角色非常有效,尽管我可能会决定进一步完善结构。我必须能够在层次结构中添加"敌人"类。为了满足敌人的要求,我需要添加一些与打败敌人的经验/点数、战利品表等相关的数据结构/方法。

问题是,我在哪里添加这些结构?将它们添加到baseccharacter似乎是一个坏主意,因为我基本上说每个角色都有敌人实体所需的方法/数据结构。我考虑过开始一个单独的类流,最终看起来像这样:

BaseCharacter--->Humanoid--->PlayableCharacter
           ---->Enemy--->EnemyHumanoid

敌人从basecharter继承。EnemyHumanoid将添加与baseccharacter ->Humanoid继承相同的方法/数据结构集。这是可行的,但意味着我不能将EnemyHumanoid转换为Humanoid,尽管事实上EnemyHumanoid满足Humanoid的要求。这也增加了冗余,因为我要让这两个继承添加完全相同的对象/方法集。

则考虑使用一个名为EnemyInterface的单独类,并以这样的继承层次结构结束:

BaseCharacter----->Humanoid----->PlayableCharacter
    |                 |                
    V                 V                
  Enemy         EnemyHumanoid   

Enemy和EnemyHumanoid都实现了EnemyInterface。然而,我现在失去了敌人<->敌人人形关系。我应该在这里使用多重继承吗?(敌人类人是从敌人和类人身上继承来的吗?)这被认为是不好的形态吗?有没有更合理的方法来做这件事?这里的例子相当简单,但是如果我最终把我的类层次结构分割得更多,它只会变得更复杂。

任何帮助都将是感激的

而不是重新安排你的类层次结构来解决这个特定的问题(参见StackUnderblow的答案,看看如何做到这一点),我建议你做一些研究基于组件的体系结构。从根本上说,比起使用一个类来描述使playablecarter独一无二的内容,你应该将一个组件(或一组组件)移植到某种基本容器上。

这种方法更加灵活,并且随着设计的发展更容易重构。例如,如果你有一个功能,某些敌人和人类都可以访问,那么你就必须将系统钩子添加到你的基类中,向不能使用该功能的敌人引入开销。这是描述一个简单问题的大量词汇,但随着游戏的发展,你会一次又一次地遇到这个问题。

下面是一个很好的关于我的建议的讨论。

Bheeshmar是对的,你正在通往地狱的道路上!

听起来你是在使用继承进行重用,而不是遵循LSP (http://en.wikipedia.org/wiki/Liskov_substitution_principle),这是通往地狱的道路。

我的一般建议是仅对is-a关系使用继承。也就是说,你可以用一种类型代替另一种类型。对于大多数解决方案,我更喜欢组合而不是继承,因为我发现它更简单。

在你的特殊情况下,为什么认为敌人不同于可玩角色?考虑在类层次结构之外设置EXP和Loot表,你可以将Humanoid传递给它并分别计算这些物品。

c++是一种多范式语言。你不必把自己局限于OO解决方案。

祝你好运!

这个怎么样?

  BaseCharacter----->Humanoid----->PlayableCharacter
                      /                 
                     /                   
                Enemy     EnemyHumanoid   

EnemyHumanoid可能只需要Humanoid的一些特性。

您正在尝试根据多个方面子类化您的baseccharacter类(错误,我不确定"aspect"在这里是正确的词,我不是英语母语者,对不起),即:

  • 形式-人形/动物等
  • 对齐-敌人/朋友/等

这总是会导致问题,正如您所观察到的:迟早您会想要创建应该从basecharter的多个子类继承的类(通常来自每个方面类别),例如。人形+敌人。在这种情况下,要么使用多重继承(由于实现问题,在c++中不推荐),要么需要重新设计代码。

通常最好的解决方案是根据前面确定的方面拆分对象。如。在一个baseccharacter对象中,你可以有两个指针,一个CharacterForm*和一个CharacterAlignment*。然后你可以独立地子类化CharacterForm(如HumanoidForm, AnimalForm等)和CharacterAlignment(如EnemyAlignment, FriendAlignment等),并根据需要组合它们。

请注意,正如Dan O建议的那样,这种方法实际上是迈向基于组件的设计的第一步。

您需要做一些类似的每次您发现自己创建的子类是其基类的子类,在不同的意义上比以前的子类(例如。在创建人形和动物之后,你需要敌人->这显然是分类你的基本角色的不同方式)。经验法则是,每个类应该只根据一个方面成为子类。

要考虑的问题是是否需要将Humanoid实例转换为BaseCharacter实例。你可能会发现事实并非如此。你真的需要遍历所有人形角色的集合吗?

如果是,定义:

Humanoid
BaseCharacter->PlayableCharacter (contains Humanoid)
            ---->Enemy---->EnemyHumanoid (contains Humanoid)

[你可以考虑将敌人抽象为定义一个具体的EnemyNonhumanoid]

另一种方法是将Humanoid定义为一个接口,并在playablecharter和EnemyHumanoid上提供一个getHumanoid()方法,在每种情况下作为句柄实现。

这个怎么样?

BaseCharacter

IBehaviour is接口

HumanoidBehaviourIBehaviour的实现

BaseCharacter包含IBehaviour

Enemy继承BaseCharacter并包含HumanoidBehaviour

PlayableCharacter继承BaseCharacter并包含HumanoidBehaviour

所以逻辑上我们将得到:Enemy is-a BaseCharacterhas-a行为HumanoidBehaviour .

可能策略设计模式在这里会有所帮助还有一本有趣的书,里面有一个很好的例子)