Я часто видел это в нашей унаследованной системе - функции, которые работают примерно так:
bool todo = false;
if(cond1)
{
... // lots of code here
if(cond2)
todo = true;
... // some other code here
}
if(todo)
{
...
}
Другими словами, функция состоит из двух частей. Первая часть выполняет какую-то обработку (потенциально содержащую циклы, побочные эффекты и т. Д.), И по ходу дела может установить флаг «todo». Вторая часть выполняется только в том случае, если был установлен флаг «todo».
Это кажется довольно уродливым способом сделать что-то, и я думаю, что большинство случаев, которые я потратил на это время, можно было бы изменить, чтобы избежать использования флага. Но действительно ли это анти-паттерн, плохая идея или совершенно приемлемый?
Первой очевидной рефакторизацией было бы разделить ее на два метода. Однако мой вопрос больше касается того, существует ли когда-либо необходимость (в современном языке OO) создать переменную локального флага, потенциально установить ее в нескольких местах, а затем использовать ее позже, чтобы решить, выполнять ли следующий блок кода.
["blacklisted-domain","suspicious-characters","too-long"]
который показывает, что применено несколько причин.Ответы:
Я не знаю об анти-паттерне, но я бы извлек из этого три метода.
Первый будет выполнять некоторую работу и возвращать логическое значение.
Второй будет выполнять любую работу, выполняемую «другим кодом»
Третий будет выполнять вспомогательную работу, если возвращенное логическое значение будет истинным.
Извлеченные методы, вероятно, будут закрытыми, если важно, чтобы второй (и всегда) вызывался только в том случае, если первый метод возвращал значение true.
Надеюсь, что назвав методы хорошо, это сделает код более понятным.
Что-то вроде этого:
Очевидно, что необходимо обсудить вопрос о приемлемости ранних возвратов, но это деталь реализации (как и стандарт форматирования кода).
Дело в том, что цель кода становится понятнее, и это хорошо ...
Один из комментариев к вопросу предполагает, что эта модель представляет запах , и я согласен с этим. Стоит взглянуть на это, чтобы увидеть, сможете ли вы прояснить намерение.
источник
todo
переменной и, вероятно, будет сложнее для понимания.if (check_if_needed ()) do_whatever ();
, там нет очевидного флага. Я думаю, что это может разбить код слишком сильно и потенциально повредить читабельности, если код достаточно прост. В конце концов, детали того, что вы делаете,do_whatever
могут повлиять на то, как вы тестируетеcheck_if_needed
, поэтому полезно хранить весь код в одном и том же экране. Кроме того, это не гарантирует, чтоcheck_if_needed
можно будет избежать использования флага - и если это произойдет, он, вероятно, будет использовать несколькоreturn
операторов для этого, возможно, расстроив строгих защитников с одним выходом.... // some other code here
в случае раннего возвратаЯ думаю, что уродство связано с тем, что в одном методе много кода, и / или переменные имеют неправильные имена (оба они сами по себе являются запахами кода - антипаттерны - более абстрактные и сложные вещи, IMO).
Поэтому, если вы извлекаете большую часть кода в методы более низкого уровня, как предлагает @Bill, остальное становится чистым (по крайней мере, мне). Например
Или вы можете даже полностью избавиться от локального флага, скрыв проверку флага во втором методе и используя такую форму, как
В целом, я не вижу наличия локальной переменной-флага как таковой как таковой. Какой из вышеперечисленных вариантов является более читабельным (= предпочтительным для меня), зависит от количества параметров метода, выбранных имен и того, какая форма больше соответствует внутренней логике кода.
источник
todo - действительно плохое имя для переменной, но я думаю, что это может быть все, что неправильно. Трудно быть полностью уверенным без контекста.
Допустим, вторая часть функции сортирует список, построенный по первой части. Это должно быть гораздо более читабельным:
Тем не менее, предложение Билла также верно. Это еще более читабельно:
источник
Шаблон конечного автомата выглядит хорошо для меня. Здесь есть анти-паттерны "todo" (плохое имя) и "много кода".
источник
Это зависит на самом деле. Если код, охраняемый
todo
(я надеюсь, вы не используете это имя по-настоящему, поскольку оно совершенно не мнемонично!) Является концептуально очищающим кодом, то у вас есть анти-паттерн, и вам следует использовать что-то вроде RAII C ++ или C #.using
построить, чтобы обрабатывать вещи вместо этого.С другой стороны, если это концептуально не стадия очистки, а просто дополнительная обработка, которая иногда необходима и где решение сделать это должно быть принято раньше, то написанное хорошо. Подумайте, будут ли отдельные фрагменты кода лучше подвергаться рефакторингу в их собственные функции, а также, зафиксировали ли вы значение переменной flag в ее имени, но этот базовый шаблон кода в порядке. В частности, попытка вкладывать слишком много в другие функции может сделать менее понятным то, что происходит , и это определенно будет анти-паттерном.
источник
Многие из ответов здесь будут с трудом проходить проверку сложности, некоторые выглядят> 10.
Я думаю, что это «анти-шаблонная» часть того, на что вы смотрите. Найдите инструмент, который измеряет цикломатическую сложность вашего кода - есть плагины для затмения. По сути, это измерение того, насколько сложно тестировать ваш код, и включает количество и уровни веток кода.
Как общее предположение о возможном решении, компоновка вашего кода заставляет меня задуматься о «Задачах», если это происходит во многих местах, возможно, вам действительно нужна архитектура, ориентированная на задачи - каждая задача является своей собственной объект и в середине задачи у вас есть возможность поставить в очередь следующую задачу, создав другой объект задачи и бросив его в очередь. Они могут быть удивительно просты в настройке и значительно снижают сложность некоторых типов кода - но, как я уже сказал, это полный удар в темноте.
источник
Используя приведенный выше пример pdr, так как это хороший пример, я сделаю еще один шаг.
У него было:
Поэтому я понял, что будет работать следующее:
Но не так ясно.
Итак, на оригинальный вопрос, почему бы не иметь:
И пусть SortList решит, требуется ли сортировка?
Вы видите, что ваш метод BuildList, кажется, знает о сортировке, так как он возвращает bool, указывающий как таковой, но это не имеет смысла для метода, предназначенного для построения списка.
источник
Да, это кажется проблемой, потому что вы должны отслеживать все места, где вы отмечаете флаг ВКЛ / ВЫКЛ. Лучше включать логику только внутри как вложенное условие if, а не выводить логику.
Также богатые доменные модели, в этом случае только один лайнер будет делать большие вещи внутри объекта.
источник
Если флаг установлен только один раз, переместите код
...
сразу после
... // какого-то другого кода, а
затем уберите флаг.
В противном случае разделите
... // много кода здесь
... // некоторого другого кода здесь
...
код, если это возможно, на отдельные функции, поэтому ясно, что эта функция несет одну ответственность - логику ветвления.
Везде, где возможно, разделите код внутри
... // здесь много кода
на две или более функции, некоторые из которых выполняют некоторую работу (которая является командой), а другие - либо возвращают значение todo (которое является запросом), либо создают его. очень явно они его модифицируют (запрос с использованием побочных эффектов)
Сам код, а не анти-паттерн, который происходит здесь ... Я подозреваю, что смешивание логики ветвления с фактическим выполнением вещей (команд) - это анти-паттерн, который вы ищете.
источник
Иногда я нахожу, что мне нужно реализовать этот шаблон. Иногда вы хотите выполнить несколько проверок перед продолжением операции. По соображениям эффективности расчеты, включающие определенные проверки, не выполняются, если нет необходимости в проверке. Таким образом, вы обычно видите такой код:
Это можно упростить, отделив валидацию от фактического процесса выполнения операции, так что вы увидите больше похожего на:
Очевидно, что это зависит от того, чего вы пытаетесь достичь, хотя написано так, и ваш код «успеха», и ваш код «неудачи» пишутся один раз, что упрощает логику и поддерживает одинаковый уровень производительности. Оттуда будет хорошей идеей соответствовать целым уровням проверки внутри внутренних методов, которые возвращают логические признаки успеха или неудачи, которые еще больше упрощают вещи, хотя некоторым программистам нравятся чрезвычайно длинные методы по какой-то странной причине.
источник
Это не образец . Самая общая интерпретация заключается в том, что вы устанавливаете логическую переменную и позже разветвляете ее значение. Это нормальное процедурное программирование, не более того.
Теперь ваш конкретный пример можно переписать так:
Это может быть легче читать. А может и нет. Это зависит от остального кода, который вы пропустили. Сосредоточьтесь на том, чтобы сделать этот код более лаконичным.
источник
Локальные флаги, используемые для потока управления, должны распознаваться как скрытая форма
goto
. Если флаг используется только внутри функции, его можно устранить, написав две копии функции, пометив одну как «flag is true», а другую как «flag is false» и заменив каждую операцию, которая устанавливает флаг когда он очищен, или очищает его, когда он установлен, с переходом между двумя версиями функции.Во многих случаях код, который использует использование флага, будет чище, чем любая другая альтернатива, которая использует
goto
вместо этого, но это не всегда так. В некоторых случаях использованиеgoto
для пропуска фрагмента кода может быть более чистым, чем использование флагов для этого [хотя некоторые люди могут вставить здесь определенную карикатуру хищника].Я думаю, что основной руководящий принцип должен состоять в том, чтобы программный логический поток в максимально возможной степени напоминал описание бизнес-логики. Если требования бизнес-логики описываются в терминах состояний, которые странным образом разделяются и объединяются, выполнение логики программы также может быть чище, чем пытаться использовать флаги, чтобы скрыть такую логику. С другой стороны, если наиболее естественным способом описания бизнес-правил было бы сказать, что действие должно быть выполнено, если были выполнены определенные другие действия, наиболее естественным способом выражения этого может быть использование флага, который устанавливается при выполнении последние действия и в остальном понятны.
источник