在java中将不同的子类存储为父类是否不好

在java中将不同的子类存储为父类是否不好,java,casting,Java,Casting,将对象存储为其父类并将object.getClass()与要强制转换到子类的预期类进行比较是否被认为是错误的做法 说明:作为2D游戏的一部分,我有几种类型的“游戏对象”对象,如“门户”、“玩家”、“NPC”、“胸部”等。每种对象都存储在一个二维数组中,组成每个关卡,该数组还充当更新和渲染队列,游戏对象包含关卡所需的信息。 如果我将所有对象存储为父类型GameObject,然后将它们强制转换为它们的实际类,例如(在玩家类中): 这通常会更难阅读吗?这样做可能会有什么问题?如果每个对象都使用阵列进行

将对象存储为其父类并将object.getClass()与要强制转换到子类的预期类进行比较是否被认为是错误的做法

说明:作为2D游戏的一部分,我有几种类型的“游戏对象”对象,如“门户”、“玩家”、“NPC”、“胸部”等。每种对象都存储在一个二维数组中,组成每个关卡,该数组还充当更新和渲染队列,游戏对象包含关卡所需的信息。 如果我将所有对象存储为父类型GameObject,然后将它们强制转换为它们的实际类,例如(在玩家类中):

这通常会更难阅读吗?这样做可能会有什么问题?如果每个对象都使用阵列进行交互,并且我将来可能会有其他类型的“游戏对象”,每个都具有根本不同的功能,那么什么是更好的方法呢

对不起,如果这是罗嗦,因为我真的不知道如何解释这个问题

编辑:我应该澄清类似的代码可能会从GameObject的其他子类运行,而不仅仅是玩家(即NPC或更高的类),重点是能够更改每个子类之间的交互,而无需在每次创建/更改其潜在存储类类型时更改存储级别类。感谢那些推荐
instanceof
的人,我已经更新了这个问题,将重点放在其他部分,但从现在起我可能会使用它。谢谢你的反馈

结论:我决定使用daniu答案的一个变体,其中每个游戏对象都有自己的AI子类,它扩展了上述接口的存根/适配器。因此,我不必为任何类实现反应,我可以为同一对象类型提供不同的行为,处理交互应如下所示:

getObject(x,y).getAI().react(obj);

我建议使用
instanceof
而不是比较
类本身

private void checkPosition(x, y) {
    GameObject obj = Level.getObject(x,y);
    if(obj instanceof NPC) {
       NPC npc = (NPC)obj;
       //interact with npc
    } else if(obj instanceof Chest) {
       //handle chest
    }
}
instanceof
是一个操作符,用于测试对象是否为指定类型,即
子类
接口

阅读教程以获得额外帮助

在强制转换未知对象之前,应始终使用instanceof check。这样做有助于避免运行时发生ClassCastException

而不是

if(obj.getClass() == NPC.class)
最好使用

if (obj instanceof NPC)
除非您想在不允许子类的情况下测试确切的类

另一种选择是让对象自己检查它们的位置,然后就这样做

private void checkPosition(int x, int y) {
    GameObject obj = Level.getObject(x,y);
    obj.checkPosition()
}


取决于此职位检查所需的内容。

这是访问者模式的一个用例

添加一个接口(用于可能在关卡中移动的所有内容)

和您的
游戏对象

interface GameObject { // or abstract class
    // added method
    void accept(LevelCrawler lc);  // abstract if class
}
LevelCrawler
将由
Player
类(或您在编辑中描述的
NPC
等)实现

包含
if(){…}
块中的代码

那么,你有

class Chest implements GameObject {  // I think it's a class, so probably "extends"
    void accept(LevelCrawler p) { p.handle(this); } // to call Player#handle(Chest)
}
你的代码看起来像

GameObject o = Level.getObject(x, y);
o.accept(player); // or NPC or whatever is moving right now

这样做的好处是,当您创建一个新的
GameObject
类时,您可以轻松地将新行为添加到现有的
LevelCrawler
类中,并保持
checkPosition
代码不变


玩家和NPC都在地下城中移动。

游戏中所有对象都有一个超类是正确的。我将使用
instanceof
而不是比较
getClass
返回值,但是您可以做的事情不多。另外,我会将评估包装在一个策略模式中。我编辑了我的答案,以提供几种类型的移动对象。
interface GameObject { // or abstract class
    // added method
    void accept(LevelCrawler lc);  // abstract if class
}
class Player implements LevelCrawler {
   public void accept(Chest chest) { ... }
   public void accept(NPC npc) { ... }
}
class Chest implements GameObject {  // I think it's a class, so probably "extends"
    void accept(LevelCrawler p) { p.handle(this); } // to call Player#handle(Chest)
}
GameObject o = Level.getObject(x, y);
o.accept(player); // or NPC or whatever is moving right now