плохо ли хранить разные дочерние классы как родительский класс в java - PullRequest
2 голосов
/ 03 марта 2020

Считается ли плохой практикой хранить объекты как их родительский класс и сравнивать object.getClass () с ожидаемым классом, который будет приведен к подклассу.

объяснение: как часть 2D-игры на основе тайлов Движение У меня есть несколько типов объектов GameObject, таких как «Портал», «Игрок», «NP C», «Сундук» и т. д. c. Каждый хранится в двумерном массиве, составляющем каждый уровень, который также действует как очередь обновления и рендеринга, а GameObject воплощает информацию, требуемую уровнем. Если я сохраню все объекты как родительский тип GameObject, то приведу их к их фактическому классу, например (в классе Player):

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
    }
}

Будет ли это обычно труднее читать? Какие проблемы у меня могут быть при этом? Что было бы лучшим методом, если бы каждый из них использовал массив для взаимодействия друг с другом, и в будущем у меня, вероятно, будут другие типы «GameObjects», каждый из которых имеет принципиально разные функциональные возможности.

Извините, если это Я не совсем уверен, как объяснить этот вопрос.

edit: Я должен уточнить, что подобный код может быть запущен из других подклассов GameObject, а не только из Player (ie NP C или более поздней версии). Класс), и основной упор делается на возможность изменять взаимодействие между каждым подклассом без изменения сохраняющего класса Level каждый раз, когда создается или изменяется один из его потенциально хранимых классов. спасибо тем, кто рекомендовал instanceof Я обновил вопрос, чтобы сосредоточиться на других частях, но я, вероятно, буду использовать его с этого момента. Спасибо за отзыв.

Заключение: я решил go для варианта ответа Даниу, где у каждого GameObject есть свой собственный подкласс AI, который расширяет заглушку / адаптер упомянутого интерфейса. Таким образом, мне не нужно реализовывать реакции для любого класса, я могу дать разное поведение одному и тому же типу объекта, и взаимодействие при обработке должно выглядеть следующим образом:

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

Ответы [ 3 ]

4 голосов
/ 03 марта 2020

Это вариант использования для шаблона посетителя.

Добавить интерфейс (для всего, что может перемещаться по уровню)

interface LevelCrawler {
   void accept(Chest chest);
   void accept(NPC npc);
}

и к вашему GameObject

interface GameObject { // or abstract class
    // added method
    void accept(LevelCrawler lc);  // abstract if class
}

LevelCrawler будет реализован, например, классом Player (или NPC et c, как вы описали в своем редактировании).

class Player implements LevelCrawler {
   public void accept(Chest chest) { ... }
   public void accept(NPC 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 без изменений.

Отредактированная версия с обоими Player и NPC, проходящими через подземелье.

2 голосов
/ 03 марта 2020

Вместо

if(obj.getClass() == NPC.class)

было бы лучше использовать

if (obj instanceof NPC)

, если вы не хотите проверять точный класс без использования подклассов.

Другой вариант может позволить объектам проверять свои позиции самостоятельно и просто делать

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

или

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

в зависимости от того, что необходимо для этой проверки позиции.

2 голосов
/ 03 марта 2020

Я бы рекомендовал использовать instanceof вместо сравнения самого class.

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 - это оператор для проверки того, что объект имеет заданный тип, то есть class, subclass или interface.

Для дополнительной справки прочитайте учебник здесь .

Перед приведением неизвестного объекта всегда следует использовать экземпляр проверки. Это помогает избежать исключения ClassCastException во время выполнения.

...