Это приемлемое использование instanceof?

1

Я работаю над реализацией карточной игры UNO (в основном для запуска симуляции для проверки некоторых домашних правил, но это другая история).

Для тех, кто никогда не играл в нее, это похоже на Crazy Eights. Игроки по очереди играют на карточке на стопке сброса. Карта должна соответствовать номеру или цвету. Также есть карты для розыгрыша, которые заставляют следующего игрока нарисовать две или четыре карты. Это также довольно дружелюбный к дому правила, что делает его довольно интересным.

У меня есть класс Card со value и color карты. Я бы хотел создать DrawCard который расширяет Card. Затем, при определении игровой механики, я бы использовал instanceof чтобы проверить, есть ли у меня DrawCard.

Я знаю, что этот instanceof часто проблематичен, но мне кажется, что все в порядке. Обычно карты обрабатываются одинаково, и только несколько специальных карт обрабатываются по-разному, и только в особых обстоятельствах, характерных для типа карты (это похоже на скользкую склонность сказать, хотя...)

Я мог бы просто использовать маркеры в классе Card (фактически, у каждого типа карты уже есть свое "значение"), но я все равно расширяю Card, чтобы иметь некоторые методы, которые могут иметь другие типы карт (это не просто средство идентификации). Использование instanceof представляется мне более общим, поскольку мне не нужно знать, какие значения value требуют этого особого поведения, и было бы легко, например, добавить карту Draw 8 в текущее содержимое Draw 2 и Draw 4. (Говоря это, меня заставляет задуматься, могу ли я использовать какую-то вложенную переписку или что-то в этом роде, но я не знаю)

Я знаю, что оба решения будут работать (запустите программу). Мне, используя instanceof чувствует себя лучше, но у меня нет опыта, чтобы понять, все в порядке. Это плохой дизайн?

  • 0
    вы можете найти ответы на этот пост полезными: [влияние на производительность использования instanceof в Java] [1] [1]: stackoverflow.com/questions/103564/…
  • 0
    Имеет ли карта «розыгрыш» (не класс) также ценность и цвет? Если нет, то наследование здесь не является правильным решением - наследование является отношением «является». Обратите внимание, что, если у карт «розыгрыша» есть значения или цвета, они должны иметь точно такую же семантику, чтобы их можно было рассмотреть.
Показать ещё 1 комментарий
Теги:
oop
instanceof

2 ответа

1
Лучший ответ

Короткий ответ: Не совсем приемлемо, так что да - это признак дефицита дизайна. instanceof почти всегда является запахом, за исключением редких случаев, когда библиотека пытается сделать какую-то помощь, которая является мета или иным образом уродливой, но помогает преодолеть недостаток языка/среды.

С этим мнением этот вопрос является своего рода дубликатом. См. Ответ на:

Когда допустимо использовать instanceof?

Он предлагает использовать шаблон посетителя. Это может быть правдой, если у вас действительно есть два разных типа в системе.

Вам также не нужно использовать шаблон посетителя "явно", а скорее включать его в поток вашей программы. Поэтому рассмотрим интерфейсную карту:

interface Card {
  void pick(Player player);
}

class DrawCard implements Card {
  void pick(Player player) {
    player.draw(value); // assume value passed in e.g. ctor
  }
}
  • 0
    ОК Это имеет смысл. При настройке моей игры класс управления игрой передает карту в метод игры игрока. Чтобы я мог поместить методы в интерфейс карты, чтобы определить свойства карты? Что-то вроде булева метода «должен ли следующий игрок видеть эту карту?»?
  • 0
    Это нормально, я бы просто onTaken игрока, в ответ на получение карты, затем «забрать» карту (вы можете переименовать ее в onTaken или что-то в этом роде, если это имеет больше смысла), но затем заставить реализации карт вызывать методы на игрока, чтобы продолжить ход. Это может означать добавление очков игроку (player.increaseScore) или указание игроку, что он должен делать больше вещей (player.takeMoreCards).
0

Я бы сказал, вообще лучше избегать instanceof везде, где это возможно.

Хотя это несколько расплывчато, поскольку вы не публиковали какой-либо фактический код, одним из вариантов в этом типе ситуации было бы реализовать два разных интерфейса, например, ICard и IDrawCard а также реализовать класс Card ICard а класс DrawCard оба интерфейса.

Тогда вы сможете дифференцировать класс DrawCard благодаря своему интерфейсу в сигнатурах функций и т.д. (IDrawCard на него как на объект типа IDrawCard).

Редактировать в ответ на комментарий от OP:

Что касается обработки действий после воспроизведения карты, вы можете использовать интерфейсы для переопределения функции, которая обрабатывает действия. Поскольку это контекст для этого, я бы, вероятно, рекомендовал три разных интерфейса:

  1. ICommonCard
  2. ICard
  3. IDrawCard

Где ICommonCard является универсальным интерфейсом, когда вам нужно то, что, возможно, обрабатывает, имеет некоторые универсальные методы, а два других интерфейса удовлетворяют потребностям этих двух конкретных типов.

Тогда скажите, что у вас есть метод обработчика действий с именем handleAction, который можно определить следующим образом:

void handleAction(ICard card)
{
    // do ICard stuff here
    return;
}

void handleAction(IDrawCard card)
{
    // do IDrawCard stuff here
    return;
}

И затем, когда вы вызываете эту функцию, вы можете передать объект, являющийся типом интерфейса, в перегруженную функцию (один параметр должен иметь переменную-член для каждого типа, и если она будет той или иной, передать тот, который не равен null в функции).

  • 0
    Спасибо, я, вероятно, должен использовать интерфейсы. Как это изменить, используя instanceof для их идентификации?
  • 0
    Ну, это действительно зависит от того, что именно ты пытаешься сделать. Как я уже говорил выше, вы можете ссылаться на них по их интерфейсу в сигнатурах функций и т. Д., Что может помочь дифференцировать их. В чем конкретно контекст?
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню