Я заметил, что некоторые функции, с которыми я работаю, имеют 6 или более параметров, тогда как в большинстве библиотек, которые я использую, редко можно найти функцию, которая занимает больше 3.
Часто многие из этих дополнительных параметров являются бинарными опциями для изменения поведения функции. Я думаю, что некоторые из этих бесчисленных параметров, вероятно, должны быть реорганизованы. Есть ли руководящие указания для какого числа слишком много?
functions
parameters
Дарт Эгрегиус
источник
источник
Ответы:
Я никогда не видел рекомендации, но по моему опыту функция, которая принимает более трех или четырех параметров, указывает на одну из двух проблем:
Трудно сказать, на что ты смотришь, без дополнительной информации. Скорее всего, рефакторинг, который вам нужно сделать, это разделить функцию на более мелкие функции, которые вызываются из родительского элемента в зависимости от тех флагов, которые в данный момент передаются в функцию.
Делая это, вы получаете несколько хороших результатов:
if
структуры, которая вызывает много методов с описательными именами, чем из структуры, которая делает все это в одном методе.источник
Согласно «Чистому коду: руководство по гибкому программному обеспечению», ноль - это идеал, один или два приемлемы, три в особых случаях и четыре или больше, никогда!
Слова автора:
В этой книге есть глава, рассказывающая только о функциях, где параметры обсуждаются достаточно широко, поэтому я думаю, что эта книга может быть хорошим ориентиром для определения того, сколько параметров вам нужно.
По моему личному мнению, один параметр лучше, чем никто, потому что я думаю, что более ясно, что происходит.
Как пример, на мой взгляд, второй вариант лучше, потому что более понятно, что метод обрабатывает:
против
Применительно ко многим параметрам это может быть признаком того, что некоторые переменные могут быть сгруппированы в один объект, или, в этом случае, многие логические значения могут представлять, что функция / метод выполняет больше, чем одну вещь, и в этом случае, лучше рефакторинг каждого из этих поведений в разные функции.
источник
String language = detectLanguage(someText);
. В любом из ваших случаев вы передали одинаковое количество аргументов, просто бывает, что вы разбили выполнение функции на две из-за плохого языка.Matrix.Create(input);
гдеinput
есть, скажем, .NETIEnumerable<SomeAppropriateType>
? Таким образом, вам также не нужна отдельная перегрузка, когда вы хотите создать матрицу, содержащую 10 элементов вместо 9.Если классы домена в приложении спроектированы правильно, число параметров, которые мы передаем в функцию, будет автоматически уменьшено - потому что классы знают, как выполнять свою работу, и у них достаточно данных, чтобы выполнять свою работу.
Например, скажем, у вас есть класс менеджера, который просит класс 3-го класса выполнить задания.
Если вы моделируете правильно,
Это просто
Если у вас нет правильной модели, метод будет таким
Правильная модель всегда уменьшает параметры функций между вызовами методов, поскольку правильные функции делегируются их собственным классам (единая ответственность), и у них достаточно данных для выполнения своей работы.
Всякий раз, когда я вижу, как увеличивается число параметров, я проверяю свою модель, чтобы увидеть, правильно ли я разработал модель своего приложения.
Однако есть некоторые исключения: когда мне нужно создать объект переноса или объекты конфигурации, я буду использовать шаблон построителя, чтобы сначала создавать маленькие построенные объекты, прежде чем создавать большой объект конфигурации.
источник
Один аспект, который другие ответы не затрагивают, - это производительность.
Если вы программируете на достаточно низкоуровневом языке (C, C ++, ассемблер), большое количество параметров может сильно ухудшить производительность на некоторых архитектурах, особенно если функция вызывается большое количество раз.
Когда вызов функции производится в ARM, например, первые четыре аргумента помещаются в регистрах ,
r0
чтобыr3
и остальные аргументы должны быть в стек. Если количество аргументов меньше пяти, это может существенно повлиять на критические функции.Для функций, которые вызываются очень часто, даже тот факт , что программа должна установить аргументы , прежде чем каждый вызов может повлиять на производительность (
r0
вr3
может быть перезаписана вызываемой функции и должны быть заменены до следующего вызова) так что в этом отношении нулевые аргументы являются лучшими.Обновить:
KjMag поднимает интересную тему встраивания. Встраивание в некотором роде смягчит это, поскольку позволит компилятору выполнять те же оптимизации, которые вы могли бы выполнить, если бы писали в чистой сборке. Другими словами, компилятор может видеть, какие параметры и переменные используются вызываемой функцией, и может оптимизировать использование регистров, чтобы минимизировать чтение / запись в стеке.
Есть некоторые проблемы с наклоном, хотя.
inline
во всех случаях его считали обязательным.inline
либо фактически выдают вам ошибки при их обнаружении.источник
inline
.)Когда список параметров увеличится до пяти, рассмотрите возможность определения "контекстной" структуры или объекта.
Это в основном просто структура, которая содержит все необязательные параметры с некоторыми разумными значениями по умолчанию.
В процедурном мире C подойдет простая структура. В Java C ++ достаточно простого объекта. Не связывайтесь с геттерами или сеттерами, потому что единственная цель объекта - хранить «общедоступные» устанавливаемые значения.
источник
Нет, стандартного руководства нет
Но есть некоторые приемы, которые могут сделать функцию с большим количеством параметров более сносной.
Вы можете использовать параметр list-if-args (args *) или параметр dictionary-of-args (kwargs
**
)Например, в Python:
Выходы:
Или вы можете использовать синтаксис определения литерала объекта
Например, вот JavaScript-вызов jQuery для запуска AJAX GET-запроса:
Если вы посмотрите на класс jQuery ajax, вы можете установить гораздо больше (примерно 30) свойств; главным образом потому, что связь ajax очень сложна. К счастью, буквальный синтаксис объекта облегчает жизнь.
C # intellisense предоставляет активную документацию параметров, поэтому весьма часто можно увидеть очень сложные схемы перегруженных методов.
Динамически типизированные языки, такие как python / javascript, не имеют такой возможности, поэтому гораздо чаще можно увидеть аргументы ключевых слов и определения литералов объектов.
Я предпочитаю определения литералов объектов ( даже в C # ) для управления сложными методами, потому что вы можете явно видеть, какие свойства устанавливаются при создании экземпляра объекта. Вам придется проделать немного больше работы для обработки аргументов по умолчанию, но в долгосрочной перспективе ваш код будет намного более читабельным. Используя определения литералов объектов, вы можете избавиться от зависимости от документации, чтобы понять, что делает ваш код на первый взгляд.
ИМХО, перегруженные методы сильно переоценены.
Примечание. Если я правильно помню, управление доступом только для чтения должно работать для литеральных конструкторов объектов в C #. По сути, они работают так же, как установка свойств в конструкторе.
Если вы никогда не писали какой-либо нетривиальный код на языке динамически типизированного (python) и / или функционального / прототипа на основе javaScript, я настоятельно рекомендую попробовать его. Это может быть полезным опытом.
Вначале может быть страшно сломать вашу зависимость от параметров для конечного, всеобъемлющего подхода к инициализации функции / метода, но вы научитесь делать намного больше с вашим кодом, не добавляя ненужной сложности.
Обновить:
Я, вероятно, должен был предоставить примеры, чтобы продемонстрировать использование в статически типизированном языке, но в настоящее время я не думаю о статически типизированном контексте. По сути, я делал слишком много работы в динамически типизированном контексте, чтобы внезапно переключиться обратно.
То , что я действительно знаю, объект синтаксиса буквальное определение вполне возможно в статически типизированных языках (по крайней мере , в C # и Java) , потому что я использовал их раньше. В статически типизированных языках они называются «инициализаторами объектов». Вот несколько ссылок, чтобы показать их использование в Java и C # .
источник
Лично, больше чем 2 - то, где мой код запускает тревогу запаха. Когда вы рассматриваете функции как операции (то есть перевод из ввода в вывод), редко используется более двух параметров в операции. Процедуры (то есть ряд шагов для достижения цели) потребуют больше ресурсов и иногда являются лучшим подходом, но в большинстве языков в наши дни не должно быть нормой.
Но опять же, это скорее правило, чем правило. У меня часто есть функции, которые принимают более двух параметров из-за необычных обстоятельств или простоты использования.
источник
Очень похоже на то, как говорит Эван Плейс, я большой поклонник простого передачи ассоциативных массивов (или сопоставимой структуры данных вашего языка) в функции, когда это возможно.
Таким образом, вместо (например) этого:
Перейти на:
Wordpress делает много вещей таким образом, и я думаю, что это работает хорошо. (Хотя мой пример кода выше является мнимым, а не сам пример из Wordpress.)
Этот метод позволяет вам легко передавать много данных в ваши функции, но при этом освобождает вас от необходимости запоминать порядок, в котором каждый из них должен быть передан.
Вы также оцените эту технику, когда придет время для рефакторинга - вместо того, чтобы потенциально изменять порядок аргументов функции (например, когда вы понимаете, что вам нужно передать еще один аргумент), вам не нужно изменять параметр своих функций список на всех.
Это не только избавляет вас от необходимости переписывать определение вашей функции, но и избавляет вас от необходимости менять порядок аргументов при каждом вызове функции. Это огромная победа.
источник
В предыдущем ответе упоминался надежный автор, который утверждал, что чем меньше параметров у ваших функций, тем лучше вы работаете. Ответ не объясняет, почему, но книги объясняют это, и вот две из наиболее убедительных причин, почему вам нужно принять эту философию и с которыми я лично согласен:
Параметры относятся к уровню абстракции, который отличается от уровня функции. Это означает, что читатель вашего кода должен будет подумать о природе и назначении параметров ваших функций: это мышление «более низкого уровня», чем у названия и цели соответствующих функций.
Вторая причина, чтобы у функции было как можно меньше параметров, это тестирование: например, если у вас есть функция с 10 параметрами, подумайте, сколько комбинаций параметров вам нужно, чтобы покрыть все тестовые случаи, например, для единицы контрольная работа. Меньше параметров = меньше тестов.
источник
Чтобы предоставить больше контекста вокруг рекомендации относительно идеального числа аргументов функции, равного нулю, в книге Роберта Мартина «Чистый код: Руководство по гибкому программному обеспечению», автор говорит в качестве одного из своих пунктов следующее:
Для
includeSetupPage()
приведенного выше примера вот небольшой фрагмент его переработанного «чистого кода» в конце главы:Авторская «школа мысли» утверждает для небольших классов, малого (в идеале 0) количество аргументов функций и очень маленькие функции. Хотя я также не полностью согласен с ним, я нашел это наводящим на размышления, и я чувствую, что идея нулевых аргументов функции как идеала может стоить рассмотреть. Кроме того, обратите внимание, что даже его небольшой фрагмент кода выше имеет также функции с ненулевым аргументом, так что я думаю, что это зависит от контекста.
(И как уже указывали другие, он также утверждает, что большее количество аргументов усложняет задачу с точки зрения тестирования. Но здесь я в основном хотел выделить приведенный выше пример и его обоснование для аргументов с нулевой функцией.)
источник
В идеале ноль. Один или два в порядке, три в некоторых случаях.
Четыре или более обычно плохая практика.
Наряду с принципами единой ответственности, которые отметили другие, вы также можете думать об этом с точки зрения тестирования и отладки.
Если есть один параметр, зная его значения, протестировать их и найти ошибку с ними «относительно легко, поскольку есть только один фактор. По мере увеличения факторов общая сложность быстро увеличивается. Для абстрактного примера:
Рассмотрим программу «Что надеть в такую погоду». Посмотрите, что он может сделать с одним входом - температура. Как вы можете себе представить, результаты того, что надеть, довольно просты в зависимости от этого фактора. Теперь подумайте, что может / может / должна сделать программа, если она действительно прошла температуру, влажность, точку росы, осадки и т. Д. Теперь представьте, как трудно будет отладить, если она даст «неправильный» ответ на что-то.
источник