Шаблон для пробования различных методов при возникновении исключения

Вот вопрос, чтобы раскрыть мой недостаток опыта: у меня есть метод Сделай что-нибудь(), который выдает исключение, если ему не удается сделать это чисто. Если это не удается, я несколько раз пробую менее точный метод DoSomethingApproximately () в надежде, что он найдет достаточно хорошее решение; если это тоже не удается, я, наконец, вызываю DoSomethingInaccurateButGuaranteedToWork (). Все три являются методами, принадлежащими этому объекту.

Два вопроса: во-первых, приемлем ли этот (по общему признанию уродливый) шаблон, или есть более элегантный способ?

Во-вторых, как лучше всего отслеживать, сколько раз я вызывал DoSomethingApproximately (), учитывая, что это может вызвать исключение? В настоящее время я храню в объекте переменную iNoOfAttempts и вкладываю блоки try ... это ужасно, и мне стыдно.

Да; Я предполагаю, что большинство решений должны быть в значительной степени независимыми от языка, если возможна обработка исключений.

Joel in Gö 24.09.2008 16:35
Повышение качества Laravel с помощью принципов SOLID: Лучшие практики и примеры
Повышение качества Laravel с помощью принципов SOLID: Лучшие практики и примеры
Когда мы говорим о том, как сделать следующий шаг в качестве разработчика, мы должны понимать, что качество кода всегда является основным фокусом на...
Принципы SOLID - лучшие практики
Принципы SOLID - лучшие практики
SOLID - это аббревиатура, обозначающая пять ключевых принципов проектирования: принцип единой ответственности, принцип "открыто-закрыто", принцип...
3
1
250
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вернуть код ошибки вместо создания исключения.

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

   bool result = DoSomething();
   while (!result && tries < MAX_TRIES) {
       result = DoSomethingApproximately(); //This will increment tries
       if (tries > THRESHOLD) {
           result = DoSomethingThatAlwaysWorks();
       }
   }
Ответ принят как подходящий

Вы никогда не должны использовать исключения для потока управления вашего приложения.

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

Я не согласен. если DoSomethingApproximately () и DoSomethingThatAlwaysWorks () на самом деле являются функциями обработки ошибок, то исключения вполне могут быть подходящим способом для этого.

Anders Sandvig 24.09.2008 16:40

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

Vinko Vrsalovic 24.09.2008 16:43

Да, конечно. Мы должны предположить, что DoSomething () делает то, что должен делать, если только не произойдет что-то неожиданное ...;)

Anders Sandvig 24.09.2008 16:46

Нет, мы не должны ничего предполагать. Спрашивающий даже, кажется, ожидает, что метод потерпит неудачу ...

Vinko Vrsalovic 24.09.2008 16:56

Кроме того, вы должны быть осторожны, чтобы не скрывать исключения, которые являются реальными проблемами, а не «ожидаемыми» проблемами. Тем не менее, +1 не использует исключения для управления потоком.

user7116 24.09.2008 17:24

Я только очень редко ожидаю, что это случится. Но я понимаю, что такое управление потоком.

Joel in Gö 24.09.2008 20:49

Как насчет (псевдокода):

try{ return doSomething(); }
catch(ExpectedException) { ...not much here probably...}

for(i = 0 to RETRIES){
try{ return doSomethingApproximately; }
catch(ExpectedException) { ...not much here probably...}
}

doSomethingGuaranteed();

Дополнение:

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

Иногда мне нравится иметь параметр, позволяющий вызывающему абоненту указывать, следует ли указывать общие режимы отказа через исключение или код возврата. Рассмотрим что-то вроде «войти на сервер X с учетными данными Y». Если вызывающий абонент ожидает, что попытка может потерпеть неудачу (например, если у него есть список серверов, и он будет пытаться, пока не добьется успеха), использование метода исключения исключения бесполезно. С другой стороны, если код ожидает, что логин будет просто работать, генерирование исключения может устранить необходимость проверки ошибок на стороне клиента при попытке, если возникшее исключение будет тем, которое клиент может уловить.

supercat 04.11.2010 22:50

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

Queue<Action> actions = new Queue<Action>(new Action[] {
   obj.DoSomething,
   obj.DoSomethingApproximately,
   obj.DoSomethingApproximately,
   obj.DoSomethingApproximately,
   obj.DoSomethingApproximately,
   obj.DoSomethingGuaranteed
});

actions.First(a => {
   try {
      a();
      return true;
   } catch (Exception) {
      return false;
   }
});

Другие вопросы по теме