最近我决定看看Java,所以我还是很新的,也是OO编程的方法,所以我想在学习更多东西之前先做一些事情,(我想它永远不会很快开始有良好做法)。
我现在正在编写一个2D游戏,但我认为我的问题适用于任何非平凡的项目。为了简单起见,我将从游戏中提供示例。
我有不同种类的僵尸,但它们都具有相同的属性(x,y,健康,攻击等)所以我写了一个界面 Zombie,我通过WalkingZombie,RunningZombie TeleportingZombie等实现。这是最好的事吗?我最好使用抽象类?还是使用超类? (我不打算部分实现功能 - 因此我选择接口而不是抽象类)
我有一个类描述主角(Survivor),因为它非常大,我想编写一个具有不同功能的接口,这样我就可以轻松地看到并分享它的结构。这是好习惯吗?或者只是浪费空间和时间?
我希望这个问题不会被评为主观,因为我认为有经验的程序员不会对这类话题产生不同意见,因为接口/超类/抽象类的使用遵循逻辑规则,因此不仅仅是个人选择
答案 0 :(得分:16)
您可以将界面视为“合同”。您正在定义一组实现此接口的类必须实现的方法。
另一方面,如果您有一些代码可能对您要实现的所有子类都是通用的,则使用抽象类。所以你可能有一个名为Shape的抽象类,它有一些公共代码,在派生类(Circle,Square等)中你可以得到特定于那些形状的代码(getArea
就是一个例子) 。但是像颜色这样的东西可能对所有形状都很常见,所以你可以在Shape抽象类中放置一个getColor
方法。
你可以把这两个想法结合起来。您可以使用实现接口的抽象类,这样可以为您提供两全其美的优势。
这些概念在OO中反复使用,因此理解它们非常重要。你似乎很顺利:)。
因此,如果你的僵尸类有一些适用于所有类型僵尸的常见行为,那么它听起来像是一个抽象类的好候选者。如果你的游戏中有其他角色(也许是GameCharacter
或者其他:),你也可以考虑创建一个界面(可能是一个UndeadMice
界面)。然后,您的Zombie
抽象类和UndeadMouse
抽象类将实现GameCharacter
接口。
答案 1 :(得分:4)
如果有疑问,我选择遵循GOF范式。
封装变化的内容: - 在自己的类中定义唯一行为。要参考上面的例子,在其单独的类中实现步行,跑步和传送的行为。这样就实现了多态行为。
相反,**聚合常见的东西** - 使用抽象类来定义多态关联中的常见行为。我在设计对象之间的关系时使用这些原则。
答案 2 :(得分:3)
是的,我认为你正在通过抽象类的接口走向正确的轨道。
您可能想要制作的任何具体僵尸都可以拥有您想要实现的步行,跑步或传送功能的任意组合。
我认为现代编程理论尽可能地阻止继承,因为它从长远来看会抑制可重用性和灵活性。相反,使用接口和组合来实现灵活性而无需“紧耦合”。
在没有继承的情况下重用代码的一种方法,您可以应用'优先构成而不是继承'范例。
我觉得Josh Bloch的'Effective Java'(第2版)可以被视为“当前思考”...
因此,您可以将所有行为实现为独立类,然后通过实现和实现方式为每个僵尸实现提供自己的行为组合。组合物..
希望这是有道理的&帮助...
答案 3 :(得分:1)
我会把Zombie写成一个抽象类来避免重新定义字段x,y,health等...
对于Survivor类,我只是声明公开要在外部使用的函数。我在类的顶部声明了公共函数。当只有一个实现它的类时,声明一个接口会无用地添加一个文件来维护。避免它。
答案 4 :(得分:1)
没有人同意在超级/抽象类上使用接口;)
使用接口和超级/抽象类的主要原因是启用多态。例如,在你的情况下,你有东西在屏幕上移动(播放器和僵尸等)。为什么不使用相同的方法让它们全部在屏幕上移动?也许从一个名为“Movable”的对象或类似的东西继承将要在屏幕上移动的所有内容。
如果你真的喜欢这些东西,你可能也想看看mixins。这不是Java直接支持的东西,而是为它构建了库。
答案 5 :(得分:1)
我有不同种类的僵尸,但它们都具有相同的属性(x,y,健康, 攻击等)所以我写了一个界面Zombie,我通过WalkingZombie实现, RunningZombie TeleportingZombie等。这是最好的事情吗?我最好还是一个 抽象类?还是有超级班?
抽象类将是僵尸的超级类。在某种意义上,界面也会是你的僵尸的超类(超级界面?)。
公共属性至少建议公共属性的抽象基类。
(我不打算部分实现功能 - 因此我选择了一个接口 而不是抽象类)
不确定你的意思。
如果您有不同种类的怪物(地精,兽人等),您可能会发现这些怪物会想要属于不同的基类。这会建议一个界面。
我将从一个抽象基类开始,看看代码在编写时告诉你的内容。
我有一个类描述主角(幸存者),因为它非常大我 想要编写一个具有不同功能的界面,这样我就可以轻松看到和 分享它的结构。这是好习惯吗?或者它只是浪费空间和 时间?
你的幸存者是所谓的玩家角色(而不是非玩家角色 - 游戏中通常不会攻击你的幸存者的人)。
大多数游戏都将所有这些角色类型视为某种怪物,因为它们都有许多共同属性(健康。魔法,宝物,武器等)。
所以也许这更像是一个接口的参数。
请参阅:
Using inheritance and polymorphism to solve a common game problem Class diagram examples for RPG (Role Playing Game) designing class hierarchy for typical characters in role playing game
答案 6 :(得分:0)
我不认为在你的情况下你的界面和类结构与现实很好地吻合。事实上,我相信(如果我错了,请纠正我),每个僵尸都可以走路,跑步,传送等,具体取决于它的位置。
因此,你应该拥有一个僵尸类或界面,并拥有修改僵尸状态的动作。该操作可能是一个接口或一个抽象类,因此您可以在不知道具体操作的情况下将任何操作应用于僵尸(例如action.perform(zobie)
)。
如果您有不同种类的僵尸,例如三足僵尸和单臂僵尸,您可能想要实现处理僵尸内容的不同类,例如显示自己或验证状态变化(例如特殊类型僵尸可能不接受传送)。
答案 7 :(得分:0)
就你的Zombie示例来说,界面会很好,除非你有共同的代码,你想要所有的僵尸做。
假设你有一个Move
方法,让步行僵尸走路,跑步僵尸跑等等。但是,如果你想要“移动”让任何一种僵尸做一些常见的事情,那么界面会迫使你重复代码,因为你不能将一个正文放在一个接口中。
答案 8 :(得分:0)
我的观点是你最好使用名为 Creature 的抽象类作为所有类型的生物的超级类,并将其扩展到所有类型僵尸的 Zombie 。
而且你还需要一个界面..来定义一个生物可以做的事情。
喜欢也许,走路,或抓爪,或尖叫......
你需要一个抽象类的原因是禁用 Creature 的实例化,你不想让一个生物不知道它是什么生物,对吗?