Мой коллега заявляет, что логические значения в качестве аргументов метода недопустимы . Они заменяются нумерацией. Сначала я не увидел никакой пользы, но он привел мне пример.
Что легче понять?
file.writeData( data, true );
Или
enum WriteMode {
Append,
Overwrite
};
file.writeData( data, Append );
Теперь я понял! ;-)
Это определенно пример, когда перечисление в качестве второго параметра делает код более читабельным.
Итак, что вы думаете по этой теме?
coding-style
boolean
enumeration
Томас Кошель
источник
источник
Ответы:
Логические значения представляют варианты «да / нет». Если вы хотите представить «да / нет», используйте логическое значение, оно не требует пояснений.
Но если это выбор между двумя вариантами, ни один из которых явно не является да или нет, тогда перечисление иногда может быть более читаемым.
источник
setLightOn(bool)
.Перечисления также допускают будущие модификации, когда вам теперь нужен третий вариант (или больше).
источник
Используйте тот, который лучше всего моделирует вашу проблему. В приведенном вами примере лучше выбрать enum. Однако были бы и другие случаи, когда логическое значение лучше. Что имеет для вас больше смысла:
или
В этом случае я мог бы выбрать логический вариант, поскольку я считаю, что он достаточно ясен и недвусмысленен, и я почти уверен, что моя блокировка не будет иметь более двух состояний. Тем не менее, второй вариант допустим, но излишне сложен, ИМХО.
источник
Для меня ни логическое значение, ни перечисление - не лучший подход. Роберт С. Мартин очень четко это уловил в своем Совете № 12 по чистому коду: устранение логических аргументов :
Если метод выполняет более одного действия, вам лучше написать два разных метода, например, в вашем случае:
file.append(data)
иfile.overwrite(data)
.Использование перечисления не проясняет ситуацию. Это ничего не меняет, это все еще аргумент флага.
источник
setVisible(boolean visible) { mVisible = visible; }
. Какую альтернативу вы бы предложили?Я думаю, вы почти ответили на это сами, я думаю, что конечная цель - сделать код более читабельным, и в этом случае перечисление сделало это, ИМО всегда лучше смотреть на конечную цель, а не на общие правила, может быть, подумайте об этом больше в качестве ориентира, т.е. перечисления часто более читабельны в коде, чем общие bools, int и т. д., но всегда будут исключения из правила.
источник
Помните вопрос, который Адлай Стивенсон задал послу Зорину в ООН во время кубинского ракетного кризиса ?
Если флаг, который у вас есть в вашем методе, имеет такую природу, что вы можете привязать его к бинарному решению , и это решение никогда не превратится в трехстороннее или n-стороннее решение, выберите логическое значение. Показания: ваш флаг называется isXXX .
Не делайте его логическим в случае переключения режима . Всегда есть на один режим больше, чем вы думали при написании метода.
Дилемма «еще один режим» преследовала, например, Unix, где возможные режимы разрешений, которые может иметь файл или каталог сегодня, приводят к странным двойным значениям режимов в зависимости от типа файла, владельца и т. Д.
источник
Я считаю, что это плохо по двум причинам:
Потому что некоторые люди напишут такие методы, как:
Это явно плохо, потому что слишком легко перепутать параметры, и, глядя на это, вы даже не представляете, что указываете. Хотя всего один bool не так уж и плохо.
Поскольку управление потоком программы с помощью простой ветки «да / нет» может означать, что у вас есть две совершенно разные функции, которые неудобно объединены в одну. Например:
На самом деле, это должно быть два метода
потому что код в них может быть совершенно другим; им, возможно, придется выполнять всевозможные различные способы обработки и проверки ошибок или, возможно, даже придется по-другому форматировать исходящие данные. Вы не можете сказать это, просто используя
Write()
или дажеWrite(Enum.Optical)
(хотя, конечно, вы можете использовать любой из этих методов, просто вызывая внутренние методы WriteOptical / Mag, если хотите).Я думаю, это зависит от обстоятельств. Я бы не стал придавать этому большого значения, кроме №1.
источник
Перечисления лучше, но я бы не назвал логические параметры «неприемлемыми». Иногда проще добавить одно маленькое логическое значение и двигаться дальше (подумайте о частных методах и т. Д.)
источник
Логические значения могут быть нормальными для языков с именованными параметрами, таких как Python и Objective-C, поскольку имя может объяснить, что делает параметр:
или:
источник
Я бы не согласился, что это хорошее правило . Очевидно, что Enum в некоторых случаях улучшает явный или подробный код, но, как правило, это кажется чрезмерным.
Сначала позвольте мне привести ваш пример: ответственность (и способность) программиста писать хороший код на самом деле не подвергается опасности из-за наличия логического параметра. В вашем примере программист мог написать такой же подробный код, написав:
или я предпочитаю более общий
Во-вторых: приведенный вами пример Enum «лучше» только потому, что вы передаете CONST. Скорее всего, в большинстве приложений по крайней мере некоторые, если не большинство временных параметров, которые передаются функциям, являются ПЕРЕМЕННЫМИ. В этом случае мой второй пример (с указанием переменных с хорошими именами) намного лучше, и Enum принесет вам небольшую пользу.
источник
У перечислений есть определенное преимущество, но вы не должны просто заменять все свои логические значения на перечисления. Есть много мест, где истина / ложь - лучший способ представить, что происходит.
Однако использование их в качестве аргументов метода немного подозрительно просто потому, что вы не можете увидеть, не копаясь в вещах, что они должны делать, поскольку они позволяют вам увидеть, что истинно / ложно самом деле означает
Свойства (особенно с инициализаторами объектов C # 3) или аргументы ключевого слова (a la ruby или python) - гораздо лучший способ пойти туда, где в противном случае вы бы использовали логический аргумент.
Пример C #:
Пример Ruby
Пример Python
Единственное, что я могу придумать, где логический аргумент метода является правильным, - это java, где у вас нет ни свойств, ни аргументов ключевого слова. Это одна из причин, по которой я ненавижу java :-(
источник
Хотя верно, что во многих случаях перечисления более читабельны и расширяемы, чем логические, абсолютное правило, что «логические значения неприемлемы», является глупым. Он негибкий и контрпродуктивный - он не оставляет места для человеческого суждения. Они являются фундаментальным встроенным типом для большинства языков, потому что они полезны - подумайте о применении его к другим встроенным типам: например, сказать «никогда не использовать int в качестве параметра» было бы просто безумием.
Это правило просто вопрос стиля, а не потенциальной ошибки или производительности во время выполнения. Лучшим правилом было бы «предпочитать перечисления логическим из соображений удобочитаемости».
Взгляните на структуру .Net. Логические значения используются в качестве параметров во многих методах. .Net API не идеален, но я не думаю, что использование логических значений в качестве параметров является большой проблемой. Всплывающая подсказка всегда дает вам имя параметра, и вы также можете создать такое руководство - заполните свои XML-комментарии к параметрам метода, они появятся во всплывающей подсказке.
Я также должен добавить, что есть случай, когда вы должны явно рефакторировать логические значения для перечисления - когда у вас есть два или более логических значения в вашем классе или в параметрах вашего метода, и не все состояния действительны (например, их недопустимо иметь оба установлены true).
Например, если у вашего класса есть такие свойства, как
И это ошибка, если оба они истинны одновременно, на самом деле у вас есть три действительных состояния, лучше выраженных как что-то вроде:
источник
Вот некоторые правила, которых может лучше придерживаться ваш коллега:
источник
Логическое значение будет приемлемым, только если вы не собираетесь расширять функциональность платформы. Enum предпочтительнее, потому что вы можете расширить перечисление и не нарушить предыдущие реализации вызова функции.
Другое преимущество Enum в том, что его легче читать.
источник
Если метод задает такой вопрос, как:
где
Аргументы логического метода кажутся абсолютно разумными.
источник
Это зависит от метода. Если метод делает что-то, что явно является истинным / ложным, тогда это нормально, например, ниже [хотя я не говорю, что это лучший дизайн для этого метода, это просто пример того, где использование очевидно].
Однако в большинстве случаев, таких как приведенный вами пример, лучше использовать перечисление. В самой .NET Framework есть много примеров, когда это соглашение не соблюдается, но это потому, что они представили это руководство по проектированию довольно поздно в цикле.
источник
Это делает вещи более явными, но действительно начинает значительно увеличивать сложность ваших интерфейсов - в чисто логическом выборе, таком как добавление / перезапись, это кажется излишним. Если вам нужно добавить дополнительную опцию (о которой я не могу думать в этом случае), вы всегда можете выполнить рефакторинг (в зависимости от языка)
источник
Перечисления, безусловно, могут сделать код более читаемым. Есть еще несколько вещей, на которые следует обратить внимание (по крайней мере, в .net)
Поскольку базовым хранилищем перечисления является int, значение по умолчанию будет равно нулю, поэтому вы должны убедиться, что 0 является разумным значением по умолчанию. (Например, в структурах все поля при создании установлены в ноль, поэтому нет способа указать значение по умолчанию, кроме 0. Если у вас нет значения 0, вы даже не можете протестировать перечисление без преобразования в int, что было бы плохой стиль.)
Если ваше перечисление является частным для вашего кода (никогда не публикуется), вы можете прекратить читать здесь.
Если ваши перечисления опубликованы каким-либо образом во внешнем коде и / или сохраняются вне программы, рассмотрите возможность их явной нумерации. Компилятор автоматически нумерует их от 0, но если вы измените порядок перечислений, не задав им значений, вы можете столкнуться с дефектами.
Я могу легально написать
Для борьбы с этим любой код, использующий перечисление, в котором вы не можете быть уверены (например, общедоступный API), должен проверять, действительно ли перечисление. Вы делаете это через
Единственное предостережение в
Enum.IsDefined
том, что он использует отражение и работает медленнее. Также существует проблема с версией. Если вам нужно часто проверять значение перечисления, вам будет лучше следующее:Проблема с версией заключается в том, что старый код может знать только, как обрабатывать 2 перечисления, которые у вас есть. Если вы добавите третье значение, Enum.IsDefined будет истинным, но старый код не обязательно сможет его обработать. Упс.
С
[Flags]
перечислениями можно сделать еще больше удовольствия , и код проверки для этого немного отличается.Я также отмечу, что для переносимости вы должны использовать call
ToString()
для enum и использоватьEnum.Parse()
при чтении их обратно. ОбаToString()
иEnum.Parse()
могут обрабатывать[Flags]
enum, поэтому нет причин не использовать их. Имейте в виду, это еще одна ловушка, потому что теперь вы не можете даже изменить имя перечисления, возможно, не нарушив код.Итак, иногда вам нужно взвесить все вышеперечисленное, когда вы спрашиваете себя: « Могу ли я уйти с помощью только bool?»
источник
ИМХО кажется, что перечисление было бы очевидным выбором для любой ситуации, когда возможно более двух вариантов. Но определенно существуют ситуации, когда логическое значение - это все, что вам нужно. В этом случае я бы сказал, что использование перечисления, в котором будет работать bool, будет примером использования 7 слов, когда подойдет 4.
источник
Логические значения имеют смысл, когда у вас есть очевидный переключатель, который может быть только одним из двух (например, состояние лампочки, включено или выключено). Помимо этого, хорошо писать его таким образом, чтобы было очевидно, что вы передаете - например, запись на диск - небуферизованная, с линейной буферизацией или синхронная - должна передаваться как таковая. Даже если вы не хотите разрешать синхронную запись сейчас (и поэтому вы ограничены двумя вариантами), стоит подумать о том, чтобы сделать их более подробными, чтобы с первого взгляда знать, что они делают.
Тем не менее, вы также можете использовать False и True (логические 0 и 1), а затем, если вам понадобится больше значений позже, разверните функцию для поддержки пользовательских значений (скажем, 2 и 3) и ваших старых значений 0/1. будет перенесен красиво, поэтому ваш код не должен сломаться.
источник
Иногда проще смоделировать другое поведение с помощью перегрузок. Чтобы продолжить ваш пример:
Этот подход ухудшается, если у вас есть несколько параметров, каждый из которых допускает фиксированный набор параметров. Например, метод, открывающий файл, может иметь несколько вариантов режима файла (открытие / создание), доступа к файлу (чтение / запись), режима совместного использования (нет / чтение / запись). Общее количество конфигураций равно декартовым произведениям отдельных опций. Естественно, в таких случаях множественные перегрузки не подходят.
В некоторых случаях перечисления могут сделать код более читаемым, хотя проверка точного значения перечисления на некоторых языках (например, C #) может быть сложной.
Часто логический параметр добавляется к списку параметров как новая перегрузка. Один из примеров в .NET:
Последняя перегрузка стала доступна в более поздней версии платформы .NET, чем первая.
Если вы знаете, что будет только два варианта, логическое значение может подойти. Перечисления расширяемы таким образом, что не повреждают старый код, хотя старые библиотеки могут не поддерживать новые значения перечисления, поэтому управление версиями нельзя полностью игнорировать.
РЕДАКТИРОВАТЬ
В новых версиях C # можно использовать именованные аргументы, которые, IMO, могут сделать вызывающий код более понятным так же, как перечисления. Используя тот же пример, что и выше:
источник
Я согласен с тем, что Enums - хороший способ пойти в методах, где у вас есть 2 варианта (и только два варианта, которые вы можете читать без enum).
например
Люблю Enums, но логическое значение тоже полезно.
источник
Это поздняя запись в старом посте, и она находится так далеко вниз по странице, что ее никто никогда не прочитает, но поскольку никто этого еще не сказал ...
Встроенный комментарий имеет большое значение для решения неожиданной
bool
проблемы. Исходный пример особенно отвратителен: представьте, что пытаетесь назвать переменную в функции declearation! Это было бы что-то вродеНо для примера допустим, что это декларация. Затем для необъяснимого логического аргумента я помещаю имя переменной во встроенный комментарий. сравнить
с участием
источник
Это действительно зависит от точного характера аргумента. Если это не да / нет или истина / ложь, то перечисление делает его более читаемым. Но с перечислением вам необходимо проверить аргумент или иметь приемлемое поведение по умолчанию, поскольку могут быть переданы неопределенные значения базового типа.
источник
Использование перечислений вместо логических в вашем примере действительно помогает сделать вызов метода более читабельным. Однако это замена моему любимому элементу пожеланий в C # - именованным аргументам в вызовах методов. Этот синтаксис:
будет прекрасно читаемым, и тогда вы сможете делать то, что должен делать программист, а именно выбирать наиболее подходящий тип для каждого параметра в методе, независимо от того, как он выглядит в среде IDE.
C # 3.0 допускает именованные аргументы в конструкторах. Я не знаю, почему они не могут сделать это и с помощью методов.
источник
Только логические значения
true
/false
. Так что непонятно, что это из себя представляет.Enum
могут иметь значащие имена, напримерOVERWRITE
,APPEND
и т.д. Так что перечисления лучше.источник