Являются ли переменные флага злыми? Являются ли перечисленные ниже переменные глубоко аморальными, и стоит ли их использовать?
«Булевы или целочисленные переменные, которым вы присваиваете значение в определенных местах, а затем внизу, вы проверяете, затем в другом, что-то делаете или нет, как, например, используя
newItem = true
затем несколько строк нижеif (newItem ) then
»
Я помню, как делал пару проектов, в которых я полностью пренебрегал использованием флагов и в итоге получил лучшую архитектуру / код; однако, в других проектах, над которыми я работаю, это обычная практика, и когда код увеличивается и добавляются флаги, спагетти IMHO также растут.
Вы бы сказали, что есть случаи, когда использование флагов является хорошей практикой или даже необходимо? Или вы согласитесь, что использование флагов в коде - это ... красные флаги, и их следует избегать / реорганизовывать; мне, я просто делаю с выполнением функций / методов, которые вместо этого проверяют состояния в реальном времени.
источник
newItem = true
несколько строк нижеif (newItem ) then
Ответы:
Проблема, с которой я столкнулся при поддержке кода, использующего флаги, заключается в том, что число состояний быстро растет, и почти всегда существуют необработанные состояния. Один пример из моего собственного опыта: я работал над кодом, который имел эти три флага
Эти три создали восемь состояний (на самом деле, были и два других флага). Код не охватывал все возможные комбинации значений, и пользователи видели ошибки:
Оказалось, что были ситуации, когда предположение в приведенном выше утверждении было ложным.
Флаги имеют тенденцию соединяться со временем, и они скрывают фактическое состояние класса. Вот почему их следует избегать.
источник
Вот пример, когда флаги полезны.
У меня есть кусок кода, который генерирует пароли (используя криптографически безопасный генератор псевдослучайных чисел). Вызывающий метод выбирает, должен ли пароль содержать заглавные буквы, строчные буквы, цифры, базовые символы, расширенные символы, греческие символы, кириллицу и юникод.
С флагами вызвать этот метод легко:
и это может быть даже упрощено до:
Без флагов, какой будет подпись метода?
называется так:
Как отмечено в комментариях, другим подходом будет использование коллекции:
Это гораздо более читабельно по сравнению с набором
true
иfalse
, но все же имеет два недостатка:Основным недостатком является то, что для того, чтобы разрешить объединенные значения, как
CharacterSet.LettersAndDigits
вы пишете что-то вроде этого вGenerate()
методе:возможно переписать так:
Сравните это с тем, что у вас есть, используя флаги:
Второй, очень незначительный недостаток заключается в том, что неясно, как будет вести себя метод, если вызываться так:
источник
newItem = true
несколько строк нижеif (newItem ) then
Огромный функциональный блок - это запах, а не флаги. Если вы установите флаг в строке 5, тогда проверьте только флаг в строке 354, тогда это плохо. Если вы установите флаг в строке 8 и проверьте флаг в строке 10, это нормально. Кроме того, один или два флага на блок кода - это хорошо, 300 флагов в функции - это плохо.
источник
Обычно флаги могут быть полностью заменены некоторой разновидностью шаблона стратегии с одной реализацией стратегии для каждого возможного значения флага. Это значительно упрощает добавление нового поведения.
В критических ситуациях производительности стоимость косвенного обращения может появиться и сделать деконструкцию в четкие флаги необходимыми. Тем не менее, мне трудно вспомнить ни одного случая, когда мне действительно пришлось это сделать.
источник
Нет, флаги - это не плохо и не зло, которое нужно рефакторизовать любой ценой.
Рассмотрим вызов Java Pattern.compile (строковое регулярное выражение, int flags) . Это традиционная битовая маска, и она работает. Посмотрите на константы в java и везде, где вы видите группу из 2 n, вы знаете, что там есть флаги.
В идеальном рефакторированном мире вместо этого можно использовать EnumSet, где константы являются значениями в перечислении, а документация гласит:
В идеальном мире этот вызов Pattern.compile становится
Pattern.compile(String regex, EnumSet<PatternFlagEnum> flags)
.Все, что сказал, это все еще флаги. С ним гораздо проще работать,
Pattern.compile("foo", Pattern.CASE_INSENSTIVE | Pattern.MULTILINE)
чем когда-либо,Pattern.compile("foo", new PatternFlags().caseInsenstive().multiline())
или каким-то другим способом пытаться делать то, для чего действительно нужны флаги.Флаги часто видны при работе с вещами системного уровня. При взаимодействии с чем-либо на уровне операционной системы у кого-то, вероятно, будет где-то флаг - будь то возвращаемое значение процесса, или разрешения файла, или флаги для открытия сокета. Попытка рефакторинга этих экземпляров во время охоты на ведьм против воспринимаемого запаха кода, скорее всего, приведет к худшему коду, чем если бы кто-то использовал принятый и понял флаг.
Проблема возникает, когда люди неправильно используют флаги, сбрасывая их вместе и создавая набор флагов разных типов, не связанных между собой, или пытаясь использовать их там, где они вообще не являются флагами.
источник
Я предполагаю, что мы говорим о флагах в сигнатурах методов.
Использование одного флага достаточно плохо.
Это ничего не будет значить для ваших коллег, когда они увидят это. Им нужно будет посмотреть исходный код метода, чтобы определить, что он делает. Вы, вероятно, окажетесь в том же положении несколько месяцев спустя, когда забудете, в чем заключается ваш метод.
Передача флага методу обычно означает, что ваш метод отвечает за множество вещей. Внутри метода вы, вероятно, делаете простую проверку на строки:
Это плохое разделение проблем, и вы обычно можете найти способ обойти это.
У меня обычно есть два отдельных метода:
Это будет иметь больше смысла с именами методов, которые применимы к проблеме, которую вы решаете.
Прохождение нескольких флагов в два раза хуже. Если вам действительно нужно передать несколько флагов, рассмотрите возможность их инкапсуляции в классе. Даже тогда вы все равно столкнетесь с той же проблемой, поскольку ваш метод, вероятно, выполняет несколько задач.
источник
Флаги и большинство временных переменных являются сильным запахом. Скорее всего, они могут быть реорганизованы и заменены методами запросов.
После доработки:
Флаги и временные переменные при выражении состояния должны быть реорганизованы в методы запросов. Значения состояния (логические значения, целые числа и другие примитивы) должны почти всегда скрываться как часть деталей реализации.
Флаги, которые используются для управления, маршрутизации и общего выполнения программы, могут также указывать на возможность реорганизовать разделы структур управления в отдельные стратегии или фабрики, или что-либо, что может быть ситуативно подходящим, которые продолжают использовать методы запроса.
источник
Когда мы говорим о флагах, мы должны знать, что они изменятся с течением времени выполнения программы и что они будут влиять на поведение программы в зависимости от их состояний. Пока у нас есть четкий контроль над этими двумя вещами, они будут отлично работать.
Флаги могут отлично работать, если
Если есть много флагов, хорошей работе над дизайном должно предшествовать, так как флаги начинают играть ключевую роль в поведении программы. Вы можете перейти к диаграммам состояния для моделирования. Такие диаграммы также работают как документация и визуальное руководство при работе с ними.
Пока эти вещи на месте, я думаю, что это не приведет к беспорядку.
источник
Из вопроса я предположил, что QA означает флаговые (глобальные) переменные, а не биты параметра функции.
Есть ситуации, когда у вас не так много других возможностей. Например, без операционной системы вы должны оценивать прерывания. Если прерывание возникает очень часто, и у вас нет времени на длительную оценку в ISR, не только разрешается, но иногда даже рекомендуется устанавливать только некоторые глобальные флаги в ISR (вы должны тратить как можно меньше времени в ISR), и оценить эти флаги в вашем основном цикле.
источник
Я не думаю, что что- либо является абсолютным злом в программировании, никогда.
Есть еще одна ситуация, когда флаги могут быть в порядке, которые здесь еще не упоминались ...
Рассмотрим использование замыканий в этом фрагменте Javascript:
Внутренняя функция, передаваемая в «Array.forEach», не может просто «вернуть true».
Следовательно, вы должны держать государство снаружи с флагом.
источник