Что-то может пойти не так, но это не исключение - PullRequest
10 голосов
/ 15 июля 2010

Я часто нахожусь в ситуации, когда у меня есть метод, в котором что-то может пойти не так, но исключение будет неправильно использовать, потому что оно не является исключением.

Например:

IРазрабатываю монопольную игру.В классе Bank есть метод buyHouse и поле, которое подсчитывает количество оставшихся домов (в монополии 32 дома).Что-то, что может пойти не так, как надо, это игрок, покупающий дом, когда осталось 0.Как я должен справиться с этим.Вот 3 подхода, которые я могу придумать.

1. public void buyHouse(Player player, PropertyValue propertyValue)
{
    if(houseCount < 0) throw new someException;
    ....
    //Not really an exceptional situation
}

2. public boolean buyHouse(Player player, PropertyValue propertyValue)
{
    if(houseCount < 0) return false;
    ....
    //This I think is the most normal approach but changing something
    //and returning if it was a success seems bad practice to me.
}

3. public boolean housesLeft()
{
    if(houseCount > 0) return true;

    return false;

    //Introducing a new method. But now I expect the client to call this method
    //first before calling buyHouse(). 
}

Что бы вы сделали?

Ответы [ 10 ]

12 голосов
/ 15 июля 2010

Я бы сделал 3 и 1 вместе. Правильное использование API заключается в проверке наличия домов перед их покупкой. Однако если разработчик забыл это сделать, выдается исключение времени выполнения.

Если это многопоточная ситуация (когда многие люди покупают дом одновременно), она усложняется. В этом случае я действительно рассмотрю проверенное исключение, если не метод tryToBuyAHouse, который возвращает логическое значение, а исключение времени выполнения для метода buyHouse.

5 голосов
/ 15 июля 2010

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

Думайте об исключительных ситуациях как о случаях, когда вы хотите уведомить программиста о том, что что-то пошло не так, и вы не хотите, чтобы они это игнорировали.Использование простого логического возвращаемого значения не является «правильным», поскольку программист может просто игнорировать его.Также хорошая идея иметь метод, который должен вызываться для проверки доступности домов.Но помните, что программисты в некоторых случаях забудут назвать это.В этом случае исключение служит для напоминания им, что им нужно вызвать метод, чтобы проверить, что дом существует, прежде чем приобретать его.

Итак, я бы предоставил метод, чтобы проверить, что дома есть, и ожидать, что людибудет вызывать его и использовать возвращаемое значение true / false.В случае, если они не вызывают этот метод или игнорируют возвращаемое значение, я бы выдал исключение, чтобы игра не перешла в плохое состояние.

4 голосов
/ 15 июля 2010

Я нахожу значение «исключительного» весьма субъективным.Это означает, что вы хотите, чтобы это значило.Вы разрабатываете интерфейс для функции, вы решаете, что является исключительным, а что нет.

Если вы не ожидаете, что buyHouse будет вызван, когда houseCount <= 0, тогда здесь исключениехорошо.Даже если вы ожидаете, что он будет вызван, вы можете перехватить исключение в вызывающей стороне для обработки этой ситуации. </p>

3 голосов
/ 15 июля 2010

Если что-то работает как положено 32 раза подряд, а затем не работает должным образом, я думаю, что вы могли бы оправдать превращение этого в исключительное условие, если бы это был единичный случай.

Учитывая ситуацию, которую вы описываете, я думаю, что использование исключений нецелесообразно, так как после продажи 32 домов банк по-прежнему будет вне их (это новое «нормальное» состояние), и обработка исключенийна самом деле довольно медленный в Java по сравнению с обычной обработкой.

Одна вещь, которую вы могли бы сделать, - это более точное отражение реального взаимодействия.В «Монополии» банкир просто скажет вам, что вы не можете купить дом, если его не осталось.

Потенциальная модель для этого выглядит следующим образом:

public House buy(Player player, PropertyValue propertyValue) {
  House propertyHouse = null;
  if (houseCount > 0) {
    propertyHouse = new House(player, propertyValue);
    houseCount--;
  }

  return propertyHouse;
}

Это также позволит вамдобавить поведение к объекту Дома и сделать процесс запроса / покупки дома немного более естественным.Если нет доступных домов, вы их не получите.

2 голосов
/ 15 июля 2010

Пара других опций:

  • Ваш метод может принять запрошенный параметр количества домов и вернуть количество фактически купленных домов после проверки доступного баланса игрока и количествадомов в наличии.Возврат нуля был бы вполне приемлемой возможностью.Конечно, вы полагаетесь на код звонка, чтобы проверить, сколько домов оно вернуло.(это вариант при возврате логического значения, где true / false указывают на 1 или ноль приобретенных домов, конечно)

  • Вариант на эту тему будет возвращать коллекцию House объекты, соответствующие количеству успешно купленных домов, которые могут быть пустой коллекцией.Предположительно, вызывающий код не сможет действовать так, как если бы он имел больше House объектов, чем вы ему дали.(это вариант возврата объекта House с нулевым значением, представляющим не купленные дома, и объектом, представляющим 1 дом, и часто является частью общего подхода к кодированию предпочтения пустых коллекций нулевым ссылкам)

  • Ваш метод может возвратить объект HousePurchaseTransaction, который сам по себе можно запросить для определения успеха или неудачи транзакции, ее фактической стоимости и т. Д.

  • Aболее богатая вариация этой темы может заключаться в том, чтобы сделать HousePurchaseTransaction абстрактным и получить два дочерних класса: SuccessfulHousePurchase и FailedHousePurchase, чтобы можно было связать различное поведение с двумя условиями результата.Установка дома на улице может потребовать от вас передать объект «SuccessfulHousePurchase» для продолжения.(это исключает опасность возврата нулевого значения, являющегося корнем более поздней ошибки нулевой ссылки, и является вариантом в шаблоне нулевого объекта)

В действительности, я подозреваю, что принятый подходзависит от того, где вы в конечном итоге распределили ответственность за размещение домов на доске, переоборудование в отели, соблюдение правил равномерного застройки, ограничение количества домов, купленных на данной улице, и т. д.

2 голосов
/ 15 июля 2010

Допускается либо (1), либо (2), в зависимости от того, считаете ли вы, что «нет домов для покупки», это обычный результат или исключительное состояние.

(3) - плохая идея по нескольким причинам:

  • нарушает инкапсуляцию (клиент должен знать слишком много о внутренностях Банка)
  • вам все равно придется проверять ошибки и делать (1) или (2) на случай, если клиент испортит
  • проблематично в многопоточных ситуациях
1 голос
/ 15 июля 2010

Помните, что вы можете использовать

return houseCount > 0;

вместо

if(houseCount > 0) return true;

return false;
1 голос
/ 15 июля 2010

Вы определяете правило и исключение для пользователя, который использует ваш API / методы:

housesLeft() можно вызвать для проверки количество домов осталось до buyHouse() называется. призвание buyHouse() всякий раз, когда число дом слева - это исключение.

Это похоже на проверку перед доступом к определенному элементу массива, вы проверяете длину массива, прежде чем пытаться получить к нему доступ, иначе возникнет исключение.

Так должно выглядеть так:

if (housesLeft() > 0) buyHouse(...);

похож на

for (int i=0; i < arrayList.length; i++) System.out.println(arrayList[i]);
1 голос
/ 15 июля 2010

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

1 голос
/ 15 июля 2010

Я бы сделал что-то вроде этого:

public boolean BuyHouse(Player player, PropertyValue propertyValue) {
      // Get houseCount
      if(houseCount <= 0) {
       // Log this to your message queue that you want to show 
       // to the user (if it has a UI)
       return false;
      }
      // Do other stuff if houses are left
}

PS: я не знаком с Java, я использую C #

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...