Иногда (редко) кажется, что создание функции, которая принимает приличное количество параметров, является наилучшим маршрутом. Однако, когда я это делаю, я чувствую, что часто выбираю порядок параметров случайным образом. Я обычно выбираю «по важности», сначала выбираю самый важный параметр.
Есть лучший способ сделать это? Существует ли «наилучшая практика» для упорядочения параметров, которая повышает ясность?
refactoring
clean-code
functions
parameters
order
Кейси Паттон
источник
источник
MessageBox.Show
. Посмотрите на это также.Ответы:
В общем, используйте это .
Напишите тест для вашей функции, тест в реальном мире.
То, что вы на самом деле хотели бы сделать с этой функцией .
И посмотри, в каком порядке ты их положил.
Если у вас уже нет (или вы не знаете) о некоторых функциях, которые выполняют нечто подобное.
В таком случае: соответствуйте тому, что они уже делают, по крайней мере, для первых аргументов.
Например, все ли они принимают документ / объект / указатель файла / ряд значений / координаты в качестве первого аргумента? Ради бога, согласитесь с этими аргументами .
Избегайте путаницы с коллегами и с самим собой .
источник
Я обычно придерживаюсь этих правил, хотя не всегда с тем же приоритетом. Я полагаю, что теперь это автоматический мыслительный процесс, и я не задумываюсь над этим, за исключением публичного проектирования API .
Воронка выбора
1. Семантика первая
Особенно в ООП, выбирайте параметры, основываясь на их семантической значимости для действия или сообщения. Подпись хорошо названного метода с хорошо названным параметром должна:
(По этим причинам иногда использование пользовательских типов или псевдонимов вместо примитивов может увеличить выразительность вашей подписи.)
2. Тогда Важность
Самый «значимый» параметр появляется первым (или следующим ...)
3. Тогда частота
Частота также имеет значение, особенно в языке, где у вас нет именованных параметров, но могут быть значения по умолчанию для позиционных параметров. Это подразумевает, что порядок параметров не меняется, и что очевидно, что вы не можете установить параметры N + 1, если вы хотите принудительно установить значение по умолчанию для N-го параметра (кроме случаев, когда ваш язык имеет понятие параметра-заполнителя) ).
Хорошей новостью для вас является то, что обычно частота связана с важностью, так что она идет рука об руку с предыдущим пунктом. И тогда, вероятно, вам нужно разработать свой API, чтобы он имел соответствующую семантику.
4. Давайте не забудем ввод / вывод
если ваш метод / функция принимает некоторый ввод и производит вывод, и последний не должен быть «возвращен» (через оператор возврата) или «брошен» (используя систему исключений), то у вас остается возможность передать значения обратно к вызывающей стороне, используя другие параметры (или входной параметр). Это относится к семантике, и в большинстве случаев будет иметь смысл, чтобы первые параметры определяли выходные данные, а последние параметры получали выходные данные.
Кроме того, другой подход, чтобы иметь меньше параметров и максимизировать семантику, заключался бы в использовании функционального подхода или определения шаблона Builder , чтобы вы могли четко составлять свои входные данные, определять свои выходные данные и извлекать их при необходимости.
(Заметьте, я не упоминаю глобальные переменные, потому что зачем использовать одну, верно?)
Некоторые вещи для рассмотрения
Удобство использования
Большинство из вышеперечисленных проявится естественным образом, если вы последуете совету ZJR : используйте его!
Рассмотреть вопрос о рефакторинге
Если вы беспокоитесь об упорядочении параметров, возможно, эта проблема коренится в вышеприведенном и в том, что ваш API плохо спроектирован. Если у вас слишком много параметров, то, скорее всего, что-то может быть скомпоновано / модульно и реорганизовано .
Учитывайте производительность
Имейте в виду, что реализации некоторых языков будут оказывать очень важное влияние на управление памятью во время выполнения при использовании параметров. Отсюда и причина того, что в книгах по стилю многих языков рекомендуется, чтобы список параметров был простым и коротким . Например, максимум 4 параметра. Я оставляю это как упражнение для вас, чтобы понять, почему.
Ответ Бевана и упоминание о рекомендациях Чистого кода , безусловно, также актуальны!
источник
Я с уважением утверждаю, что беспокойство о порядке параметров беспокоит не то, что нужно.
В книге дяди Боба « Чистый код » он убедительно утверждает, что у методов никогда не должно быть более двух аргументов - и у большинства должен быть только один, если он есть. В этом случае упорядочение является очевидным или неважным.
Как бы то ни было, я стараюсь следовать советам дяди Боба - и это улучшает мой код.
В тех редких случаях, когда метод, кажется, требует больше информации, введение объекта параметра является хорошей идеей. Обычно я считаю, что это первый шаг к открытию новой концепции (объекта), которая является ключом к моему алгоритму.
источник
Я пытаюсь поставить параметры IN первым, а параметры OUT вторым. Есть также некоторые естественные порядок, например
createPoint(double x, double y)
, сильно предпочтительнееcreatePoint(double y, double x)
.источник
addAllTo(target, something1, something2)
.Я никогда не видел документированной «наилучшей практики» по этой конкретной теме, но мой личный стандарт - перечислять их либо в том порядке, в котором они будут отображаться в методе, для которого они используются, либо, если метод более переход к слою данных. Я перечислю их в том порядке, в котором они будут отображаться в схеме БД или в методах уровня данных.
Кроме того, когда есть несколько перегрузок метода, я замечаю, что типичным способом является перечисление их, начиная с параметров, которые являются общими для всех (или большинства) методов, при этом каждый отдельный метод добавляется в конец для каждой перегрузки метода, например :
источник
Порядок: вход (ы), выход (ы), необязательные параметры.
источник
Я часто следую соглашению C / C ++, в котором
const
сначала указываются параметры (то есть параметры, которые вы передаете по значению), а затем те, которые вы передаете по ссылке. Это может не обязательно быть правильным методом вызова функций, но, если вам интересно, как каждый компилятор обрабатывает параметры, взгляните на следующие ссылки для правил, регулирующих и / или порядок, в котором параметры помещаются в стек.http://msdn.microsoft.com/en-us/library/zthk2dkh%28v=vs.80%29.aspx
http://en.wikipedia.org/wiki/Calling_convention
источник
Я обычно просто иду с упорядочением параметров «что выглядит менее кипрски». Чем меньше раз мне нужно перейти к определению метода / функции, тем лучше. И приятно иметь именованные параметры, которые описывают то, для чего они используются, так что, когда всплывает небольшая подсказка (VS), это делает его еще проще.
Если у вас есть строки и строки параметров, вы можете рассмотреть другой дизайн. Отойдите назад и посмотрите, как вы можете разбить это на больше функций / методов. Просто идея, но когда в моей функции есть дюжина параметров, это почти всегда не проблема параметров, а проблема дизайна.
источник
Использование нескольких параметров часто является четким показателем того, что вы нарушаете SRP в этом методе. Метод, которому нужно много параметров, вряд ли будет делать только одно. Исключением может быть математическая функция или метод конфигурации, где действительно необходимо несколько параметров как таковых. Я бы избегал множества параметров, поскольку дьявол избегает святой воды. Чем больше параметров вы используете в методе, тем выше вероятность того, что метод (слишком) сложен; большая сложность означает: сложнее поддерживать, а это менее желательно.
В принципе вы выбираете наугад . Конечно, вы можете подумать, что параметр A более важен, чем параметр B ; но это может быть не так для пользователей вашего API, которые считают, что B является наиболее важным параметром. Так что, даже если вы были внимательны при выборе заказа - для других это может показаться случайным .
Есть несколько выходов:
а) Тривиальный случай: не используйте более одного параметра.
б) Поскольку вы не указали, какой язык вы выбрали, есть вероятность, что вы выбрали язык с именованными параметрами . Это хороший синтаксический сахар, который позволяет вам ослабить значение упорядочения параметров:
fn(name:"John Doe", age:36)
Не каждый язык допускает такие тонкости. И что тогда?
c) Вы могли бы использовать Dictionary / Hashmap / Associative Array в качестве параметра: например, Javascript позволил бы следующее:
fn({"name":"John Doe", age:36})
что не далеко от (b).г) Конечно, если вы работаете со статически типизированным языком, таким как Java. вы можете использовать Hashmap , но вы потеряете информацию о типах (например, при работе с
HashMap<String, Object>
), когда параметры имеют разные типы (и должны быть преобразованы).Следующим логическим шагом будет передача
Object
(если вы используете Java) с соответствующими свойствами или что-то более легкое, например, структура (если вы пишете, например, C # или C / C ++).Практическое правило:
1) Лучший вариант - ваш метод вообще не нуждается в параметрах
2) Хороший случай - вашему методу нужен один параметр
3) Допустимый случай - вашему методу нужны два параметра
4) Все остальные случаи должны быть реорганизованы
источник
Часто сложный объект как параметр лучше - версия именованных параметров для бедного человека, которая работает на большинстве платформ. И открывает дверь к параметрам с поведением для загрузки.
Для примера большинства вещей, которые вы не должны делать, вы можете попробовать прочитать стандартную документацию библиотеки PHP.
источник
Я обычно заказываю их сначала по требованию, а затем по какой-то совокупной мере важности и частоты использования в соответствии с «ощущением» (можно видеть как
ORDER BY required DESC, SOME_MAGIC_FEELING(importancy,frequency)
), а не в соответствии с какой-либо конкретной практикой.Однако, как отметили другие, я думаю, что основная проблема, которая делает эту проблему, заключается в использовании слишком большого количества параметров (IMHO, что-либо> 3 слишком много), и это реальная проблема, которую вы должны решить. Есть интересный пост об этом в блоге Ребекки Мёрфи.
Я думаю, что когда у вас всего 1-3 аргумента, правильный порядок довольно очевиден, и вы просто «чувствуете», что правильно.
источник
По аналогии с ответом @Wyatt Barnetts, чем-то большим, чем несколько параметров или очень явных параметров для метода, я бы рекомендовал вместо этого передавать объект. Обычно это легче обновлять / поддерживать, легче читать и избавляет от необходимости беспокоиться о заказе . Кроме того, слишком много параметров для метода является запахом кода, и существуют общие шаблоны рефакторинга, которые вы можете использовать, чтобы помочь исправить его.
Явный пример:
Так как это довольно четко определенный пример, а сложение коммутативно (порядок не имеет значения), просто следуйте ему.
Однако, если вы добавите что-то более сложное:
Станет:
Надеюсь это поможет...
источник
Закажите его любым способом, который, по вашему мнению, выиграет от карри. Например, параметры функции в первую очередь.
источник
«Важно прежде всего» не значит много. Есть несколько условностей.
Если вы передаете вызывающий объект (часто называемый отправителем), он идет первым.
В списке должно быть свободное владение , а это значит, что вы должны знать, о чем идет речь, к тому моменту, когда вы его прочитаете. Пример:
CopyFolder (путь строки, bool рекурсивный);
Если бы вы поставили рекурсив первым, это было бы сбивающим с толку, потому что еще нет контекста. Если вы уже сейчас говорите о копировании (1) папки (2), то рекурсивный аргумент начинает иметь смысл.
Это также делает функции, подобные IntelliSense, хорошо работающими: пользователь учится, заполняя аргументы, он формирует понимание метода и того, что он делает. Аналогичным образом, перегрузки должны поддерживать одинаковый порядок для равных частей.
Тогда вы все равно можете обнаружить, что в этом отношении есть «равные» аргументы, и у вас может возникнуть соблазн позволить порядку зависеть от типа аргумента. Просто потому, что пара строк подряд, а затем пара логических значений выглядит лучше. На каком-то уровне это станет искусством, а не умением.
Меня не волнует утверждение о том, что вы должны обернуть все аргументы в объект, чтобы в итоге получить один аргумент. Это просто обманывает себя (это не делает метод менее сложным, у него все еще есть все эти аргументы, вы их просто спрятали). Это все еще может быть удобно, если вы передадите набор от метода к методу пару раз, рефакторинг, несомненно, станет намного проще, но с точки зрения дизайна он просто притворяется, что вы что-то делаете. Это не значит, что вы получите осмысленный объект, который представляет что-то, это просто набор аргументов, ничем не отличающийся от списка в объявлении метода. Это не сделает дядю Боба счастливым.
источник