Подтвердить что ты не робот

Стиль программирования: если вы вернетесь раньше, если условие охраны не выполнено?

Одна вещь, о которой я иногда задавалась, - это лучший стиль из двух приведенных ниже (если есть)? Лучше ли сразу возвращаться, если условие охраны не было удовлетворено, или вы должны делать только другие вещи, если условие охраны удовлетворено?

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

// Style 1
public SomeType aMethod() {
  SomeType result = null;

  if (!guardCondition()) {
    return result;
  }

  doStuffToResult(result);
  doMoreStuffToResult(result);

  return result;
}

// Style 2
public SomeType aMethod() {
  SomeType result = null;

  if (guardCondition()) {
    doStuffToResult(result);
    doMoreStuffToResult(result);
  }

  return result;
}
4b9b3361

Ответ 1

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

// Style 3
public SomeType aMethod() {

  if (!guardCondition()) {
    return null;
  }

  SomeType result = new SomeType();
  doStuffToResult(result);
  doMoreStuffToResult(result);

  return result;
}

Ответ 2

Будучи обученным в Jackson Structured Programming в конце 80-х, моя укоренившаяся философия всегда была "функция должна иметь единственную точку входа и единую точку выхода"; это означало, что я написал код в соответствии со стилем 2.

В последние несколько лет я понял, что код, написанный в этом стиле, часто бывает слишком сложным и трудно читается/поддерживается, и я переключился на стиль 1.

Кто говорит, что старые собаки не могут узнать новые трюки?;)

Ответ 3

Стиль 1 - это то, что ядро ​​Linux косвенно рекомендует.

От http://www.kernel.org/doc/Documentation/CodingStyle, глава 1:

Теперь некоторые люди утверждают, что наличие 8-значных отступов делает код перемещается слишком далеко вправо и затрудняет чтение на 80-символьный экран. Ответ на этот вопрос: , если вам нужно более 3 уровней отступов, вы все равно ввернуты и должны исправить вашей программы.

Стиль 2 добавляет уровни отступов, эрго, он обескуражен.

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

Ответ 4

Я не знаю, правильно ли здесь словохранитель. Обычно неудовлетворенный охранник приводит к исключению или утверждению.
Но помимо этого я бы пошел со стилем 1, потому что он держит код чище, на мой взгляд. У вас есть простой пример с одним условием. Но что происходит со многими условиями и стилем 2? Это приводит к множеству вложенных if или огромных if-условий (с ||, &&). Я думаю, что лучше вернуться из метода, как только вы это узнаете. Но это, безусловно, очень субъективно ^^

Ответ 5

Иногда это зависит от языка и того, какие типы ресурсов вы используете (например, открываете дескрипторы файлов).

В C Style 2 определенно безопаснее и удобнее, поскольку функция должна закрывать и/или выпускать любые ресурсы, которые были получены во время выполнения. Сюда входят выделенные блоки памяти, дескрипторы файлов, дескрипторы ресурсов операционной системы, такие как потоки или контексты рисования, блокировки мьютексов и любое другое. Отсрочка return до самого конца или иное ограничение количества выходов из функции позволяет программисту более легко убедиться, что он/она правильно очищает, помогая предотвратить утечку памяти, устраняет утечки, тупик и другие проблемы.

В С++, используя RAII, программирование в стиле, оба стиля одинаково безопасны, поэтому вы можете выбрать тот, который более удобен. Лично я использую стиль 1 с С++ в стиле RAII. С++ без RAII подобен C, поэтому, опять же, Style 2, вероятно, лучше в этом случае.

В таких языках, как Java с сборкой мусора, среда выполнения помогает сгладить различия между двумя стилями, поскольку она очищается после себя. Тем не менее, могут быть и тонкие проблемы с этими языками, если вы явно не закрываете некоторые типы объектов. Например, если вы построите новый java.io.FileOutputStream и не вернетесь close до его возвращения, то соответствующий дескриптор операционной системы останется открытым до тех пор, пока мусор времени выполнения не соберет экземпляр FileOutputStream, который вышел из сферы действия. Это может означать, что другой процесс или поток, который должен открыть файл для записи, может быть неспособен, пока не будет собрано экземпляр FileOutputStream.

Ответ 6

Если вы выкапываете .net-Framework, используя .net-Reflector, вы увидите, что программисты .net используют стиль 1 (или, может быть, стиль 3 уже упоминается unbeli). Причины уже упоминаются в ответах выше. и, возможно, еще одна причина - сделать код более понятным, понятным и понятным. самое главное, что этот стиль используется при проверке входных параметров, вы всегда должны это делать, если вы программируете своего рода frawework/library/dll. сначала проверьте все входные параметры, чем работайте с ними.

Ответ 7

Мартин Фаулер ссылается на этот рефакторинг как: "Заменить вложенные условные блокировки"

Если выражения /else также приводят к циклической сложности. Поэтому сложнее проверять случаи. Чтобы проверить все блоки if/else, вам может потребоваться ввести множество опций.

Где, как если бы были какие-либо защитные предложения, вы можете сначала их протестировать и более подробно разбираться с реальной логикой внутри предложений if/else.

Ответ 8

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

Ответ 9

Я бы сказал, что Style1 стал более использоваться, потому что это лучшая практика, если вы объедините его с небольшими методами.

Style2 выглядит лучше, когда у вас большие методы. Когда у вас есть... у вас есть общий код, который вы хотите выполнить независимо от того, как вы выходите. Но правильное решение состоит не в том, чтобы заставить одну точку выхода, а в том, чтобы уменьшить методы.

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

Итак, Style1 лучше, но совместим с небольшими методами. Стиль2 не так хорош, но рекомендуется, если у вас есть большие методы, которые вам не нужны, у вас есть время для разделения.

Ответ 10

Я предпочитаю использовать метод # 1 сам, его логически легче читать, а также логически больше похоже на то, что мы пытаемся сделать. (если что-то плохое происходит, выйдите из функции СЕЙЧАС, не проходите, не собирайте 200 долларов США)

Кроме того, большую часть времени вы хотели бы вернуть значение, которое не является логически возможным результатом (т.е. -1), чтобы указать пользователю, который вызвал функцию, которую функция не смогла выполнить должным образом, и принять соответствующие меры. Это также лучше подходит к методу # 1.

Ответ 11

Я бы сказал: "Это зависит от..."

В ситуациях, когда я должен выполнить последовательность очистки с более чем 2 или 3 строками перед тем, как оставить функцию/метод, я предпочел бы стиль 2, потому что последовательность очистки должна быть записана и изменена только один раз. Это означает, что легкость обслуживания легче.

Во всех остальных случаях я бы предпочел стиль 1.

Ответ 12

Номер 1 обычно является легким, ленивым и неряшливым способом. Номер 2 выражает логику чисто. То, что другие отметили, это то, что да, это может стать громоздким. Эта тенденция, однако, имеет важное преимущество. Стиль # 1 может скрыть, что ваша функция, вероятно, слишком много. Он не визуально демонстрирует сложность того, что происходит очень хорошо. То есть он не позволяет коду сказать вам "эй, это слишком сложно для этой функции". Это также делает его немного проще для других разработчиков, которые не знают ваш код, чтобы пропустить те возвращения, которые посыпались здесь и там, на первый взгляд в любом случае.

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