2009-06-20 3 views
9
procedure MyProc(Eval: Boolean); 
begin  
    if not Eval then 
     Exit; 
    /* do stuff */ 
    /* do more stuff */ 
end; 

ИЛИКакой лучший вариант?

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
     begin 
     /* do stuff */ 
     /* do more stuff */ 
     end; 

    /* no Exit needed, but now we got what I think unpleasing code: 
    having a indentation level and a begin-end statement */ 
end; 
+9

Почему вы просто не делаете что-то в своей функции, а затем добавляете оператор if из функции вызова функции? Или я чего-то не хватает? –

+0

Tomas, вы могли бы заработать очки ... Этот комментарий так же хорош, как и ответ. И это уже было поддержано несколькими ... –

+0

Thaks Thomas by formmating! Ну, я знаю, что это разрушает сплоченность, но скажем, что два stufs обрабатывают два очень разных домена, поэтому мы не можем заблокировать его в новой функции. –

ответ

1

Могу ли я просто заявить, что если вы используете вторую форму, вы не добавляете безвозмездный уровень отступов ectra. Так insrtead из:

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
     begin 
     /* do stuff */ 
     /* do more stuff */ 
     end; 

    /* no Exit needed, but now we got what I think unpleasing code: 
    having a indentation level and a begin-end statement */ 
end; 

говорят:

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
    begin 
     /* do stuff */ 
     /* do more stuff */ 
    end; 

    /* no Exit needed, but now we got what I think unpleasing code: 
    having a indentation level and a begin-end statement */ 
end; 
+0

Никакой критики не было. Дело в том, что многие люди используют ненужные уровни отступов, и это большая боль. Существует очень ужасный стиль C imndenetation, который несколько похож на первый пример и нуждается в топании. – 2009-06-20 17:41:23

+0

@Neil Butterworth: Ничего себе, это была ошибка формы, извините за это. Я не полностью разбираюсь в редакторе ответов, а также в своем английском, но в любом случае мы должны идентифицировать/* do stuff */и/* делать больше вещей * –

16

Есть случаи, когда либо метод наших правил. Как правило, однако, первый предлагает более читаемый код и лучший поток управления. Я не очень хорошо знаком с программированием Delphi, но в C# я всегда стараюсь использовать первое, когда это возможно. По внешнему виду, я не вижу причин, по которым подход должен отличаться в Delphi.

Чтобы перечислить некоторые из преимуществ:

  • Нет необходимости отступа последующий код.
  • Легче расширить до нескольких условий. (Просто добавьте дополнительные операторы if, а не логические операторы, что делает вещи более ясными.)
  • Идея о том, что вы «отказываетесь» от метода, а не выбираете, более эстетична, так как следующий код должен быть выполнен в «нормальный» случай.

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

10

Я думаю, что это вопрос предпочтения. Однако, если у вас есть ряд проверок, которые вы должны выполнить перед выполнением «реальной работы», тогда первая форма (ИМО) выглядит более аккуратной и легче отслеживать поток. Например:

procedure MyProc(Eval: Boolean); 
begin 
    if not Eval then 
     Exit; 
    if not Eval2 then 
     Exit; 
    /* do stuff */ 
    /* do more stuff */ 
end; 

v.s.

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
    begin 
     if Eval2 then 
     begin 
      /* do stuff */ 
      /* do more stuff */ 
     end; 
    end; 
end; 
+0

Второй пример не самый лучший, поскольку вы можете использовать логические операторы для его упрощения. – Noldorin

+0

@Noldorin: Справедливая точка зрения, но я не хотел чрезмерно усложнять пример. Однако вы можете представить себе сценарии, где «Eval2» представляет собой более сложную последовательность утверждений, которые не могут быть тривиально объединены с проверкой «Eval». – DaveR

+0

Да, это справедливо. Я все еще очень согласен с вашим общим моментом. – Noldorin

4

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

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

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

Особого раздражение я вижу подобные "else" в:

if (some condition) 
    return false; 
else 
    keep going; 

ли они думают, что поток управления каким-то образом собирается уйти из пункта "then"?

+0

Я согласен, что codestyle часто преувеличен. –

3

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

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

И это, кажется, используется много, учитывая тот факт, что выход (ReturnValue) был добавлен в D2009 (и FPC имея его в течение десяти лет)

0

Реальность такова, что это слишком простой пример увиливать на , Вы выберете свой подход на основе существующего соглашения - и этот пример слишком прост, чтобы принять решение по конвенции. Более интересно то, что делать с несколькими вариантами get-out-now и вложенными операторами IF - это реальная серая область.

Так что же такое конвенция? Ах ... Я прагматичный, у меня нет никаких правил. Если вы можете выпрыгнуть из окна в первых нескольких строках, я беру его, потому что мне не нужно запоминать, когда я редактирую код, который какой-то «безответный вызов функции» все равно может быть в любой момент во время работы.

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

Это более сложный вызов, если вы настраиваете вещи и должны их разорвать, так как выпрыгивание может заставлять вас жонглировать 17 состояниями Шредингера в голове при внесении изменений.

+0

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

+1

«более сложный вызов, если вы настроите ситуацию и должны оторвать их, поскольку выпрыгивание может заставить вас ...» - нет, не совсем. Поскольку исключения могут привести к тому, что код в любом случае выйдет из строя преждевременно, отрыв должен быть закодирован с использованием окончательного или автоматического подсчета ссылок. Если он работает правильно с исключениями, он будет работать и с выходом. – mghie

+0

mghie - true, только если выход через исключение, и я не люблю использовать исключения для моделирования каждого выхода кода, плюс мое «срывание» не обязательно означает объекты. также зависит от того, есть ли у вашего языка исключения - например, Пользователи vba немного коротко изменены. Я знаю, что вопрос - это Delphi, но он работает как общий вопрос, каким образом я подошел к нему. Я также должен работать в другой среде, которая не имеет никаких исключений и плохой поддержки функций, поэтому я все время занимаюсь этим. У меня нет жесткого правила - просто реализуйте то, что кажется правильным в то время. –

0

На мой взгляд, ни один из них не является правильным ответом.

Правильное решение состоит в том, чтобы включить в процедуру только части «делать вещи» и «делать больше». Затем завершите вызов процедуры в инструкции if, только при необходимости вызовите ее.

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

+0

@ Томас: Имеет смысл! Но иногда у нас есть такие сложные вещи, которые, кажется, хороши для того, чтобы инкапсулировать его во множество мелких предметов, таких как процедуры, функции или «запросы», но в других случаях кажется, что это слишком тяжело, чтобы гранулировать его слишком глубоко, даже если таким образом он проклинает сплоченность править. –

+0

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

2

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

+0

@Hardwareguy: Я полностью согласен с тобой. Артефакт кода должен иметь только одну точку выхода, поскольку, когда что-то идет не так, у нас возникает сборка исключений. –

3

Я предпочитаю:

if not Eval then Exit; 

, так как код выглядит чище, что путь.