Я реализую простую "Игру Ваше право карт" (иначе известный как выше/ниже) игра. В случае, если Вы не столкнулись с ним, прежде чем правила будут действительно просты. Используется единственный иск карт (например, основы). Одна карта оттянута за один раз, и цель состоит в том, чтобы правильно предположить, будет ли номинальная стоимость следующей карты выше или ниже, чем номинальная стоимость ранее оттянутой карты.
Логика для игры не особенно сложна, я не волнуюсь по поводу этого. Я придумал дизайн, но я не совсем доволен им. Существует несколько областей, где я уверен, что это могло быть улучшено, и это - то, относительно чего я хотел бы Ваш совет. Вот интерфейс для класса (комментарии для дополнительного понимания, не реальные комментарии):
public interface PlayYourCardsRight {
/**
* Get the number of cards remaining with higher face values than the previously
* drawn card
* @return
*/
public abstract int getNumberCardsHigher();
/**
* Get the number of cards remaining with lower face values than the previously
* drawn card
* @return
*/
public abstract int getNumberCardsLower();
/**
* Get all cards that have already been drawn in the order they were drawn in
*
*/
public abstract List<Card> getPlayedCards();
/**
* Simple prediction algorithm - if there are more cards left in the deck with
* lower face values than the previous card, then predict 'Lower', if there
* are more cards left in the deck with higher face values then predict
* 'Higher', if there are equal numbers of higher/lower cards pick 'higher' or 'lower'
* at random
*
* Prediction is an Enum (Higher/Lower/None)
*
*/
public abstract Prediction getPrediction();
/*
* Draw the next card at random
*/
public abstract void nextRound();
/**
* Specifiy what the next card should be
*
* @param card
*/
public abstract void nextRound(Card card);
}
Поскольку Вы видите, что это - все справедливо сам объяснительный и простой. Вот мои проблемы:
Я не хочу, чтобы конструктор автоматически потянул карту. Это означает, что первоначально нет никакой "ранее оттянутой карты". У меня есть a NO PREDICTION
значение в Prediction
перечисление, но, как нет никакой "ранее оттянутой карты" getNumberCardsHigher()
и getNumberCardsLower()
методы не могут возвратить нормальные значения (они не могут также возвратить нормальные значения, когда все карты из деки были оттянуты).
Очевидно, я мог просто выдать исключение, но это походит на излишество - тем более, что затем все вызовы к методам затем должны быть перенесены в попытку/выгоды. Я также недоволен возвращением отрицательного значения, так как это могло легко привести к некоторым ошибкам, если кто-то забывает/может быть побеспокоенным для проверки на них.
Все приветствующиеся предложения!
Лично я не думаю, что бросать непроверенное исключение в случае проверки аргументов - это вообще излишество - это при условии, что ваш код утверждает недопустимое состояние (Вы не должны вызывать эти методы с объектом в этом состоянии, НИКОГДА).
Обычно я использую IllegalArgumentException, чтобы показать, что был передан аргумент, который не соответствует контракту вызова метода, и IllegalStateException, чтобы показать, что объект не в том состоянии, чтобы обработать вызов метода в данный момент.
Поскольку они оба являются непроверенными исключениями, вам не нужно пытаться/ловить их, просто позвольте им всплыть, они делают то, что исключения делают отлично - они дают вам трассировку стека и говорят вам, где именно находится ваша ошибка, включая того, кто вызвал ее неправильно.
Кстати, я обычно использую какую-то строку, в вашем случае это может быть:
throw new IllegalStateException("You cannot call this method until a card has been drawn");
Логически не имеет смысла спрашивать, выше или ниже карта, чем карта, которой не существует.
Теперь, если ваш метод действительно ПРОВЕРЯЕТ это исключение, то вы должны пойти дальше и исправить свой код так, чтобы он не вызывал этот метод до тех пор, пока не вытянет карту - так что вам придется придумать, как вытянуть первую карту независимо от этого.
Примечание: Исключения предназначены только для обнаружения ошибок, избегайте их использования для управления потоком. Это означает, что вы не должны пытаться поймать исключение и использовать его для розыгрыша карты, а затем вызвать снова! Вместо этого вы должны составить программу таким образом, чтобы гарантировать, что карта будет нарисована до первого вызова методов.
Я бы сказал, что оба метода должны возвращать card.count
, когда не было вытянутой предыдущей карты. Осталось одинаковое количество младших и более высоких карт, и для обоих есть количество карт больше / меньше карт, чем ничего. Тогда ваш алгоритм будет работать и вернет NO_PREDICTION
.
Я бы лично рекомендовал иметь начальную карту до того, как игрок что-либо сделает, поскольку не имеет смысла, чтобы игрок делал что-либо до того, как первая карта будет поднята, но я думаю, что "Я не хочу, чтобы конструктор автоматически рисовал карту" означает, что вы не хотите этого делать. Если вы не хотите этого делать, я бы сделал так, чтобы функции бросали исключения, а код, который их вызывает (функция предсказания), в специальном случае в начале игры возвращал "нет предсказания" вместо того, чтобы даже пытаться их вызвать. Конец игры не является особым случаем; обе функции должны возвращать 0
, так как в колоде не осталось карт выше или ниже карты "вверх"
Также нет необходимости объявлять каждую функцию abstract
в интерфейсе, это автоматически и обязательно
Я не хочу, чтобы конструктор автоматически вытягивал карту. Это означает, что изначально нет «ранее взятой карты». У меня есть значение NO PREDICTION в перечислении Prediction, но, поскольку нет «ранее нарисованной карты», методы getNumberCardsHigher () и getNumberCardsLower () не могут возвращать разумные значения (они также не могут возвращать разумные значения, когда все карты из колоды нарисованы).
Я думаю, что путаница с API возникает из-за того, что ваш интерфейс PlayYourCardsRight
пытается моделировать две отдельные вещи: игровой движок / правила и колоду карт. Я бы переместил состояние колоды карт и методы подсчета оставшихся карт в класс Deck
. Я бы изменил API на getNumberCards [Higher / Lower] (Card)
и позволил игровому движку указывать, с какой картой вы хотите сравнивать, вместо того, чтобы ожидать, что колода запомнит, какая карта была взята последней, что я бы сделал видеть как элемент состояния игры, а не колоды.
И я настоятельно рекомендую написать несколько тестов JUnit. TDD помогает создавать целостный, несвязанный API.