Методы минимизации количества аргументов функции

13

В чистом коде написано, что «идеальное количество аргументов для функции равно нулю». Причины почему объяснены и имеют смысл. Что мне нужно, так это методы рефакторинга методов с 4 или более аргументами для решения этой проблемы.

Одним из способов является извлечение аргументов в новый класс, но это, безусловно, приведет к взрыву классов? И эти классы, скорее всего, будут заканчиваться именами, которые нарушают некоторые правила именования (заканчивающиеся на «Данные» или «Информация» и т. Д.)?

Другой метод - сделать переменные, используемые несколькими функциями, частной переменной-членом, чтобы избежать их передачи, но это расширяет область действия переменной, возможно, так, что она открыта для функций, которые на самом деле не нуждаются в ней.

Просто ищу способы минимизировать аргументы функции, приняв причины, почему это хорошая идея.

Нил Барнвелл
источник
21
Я совершенно не согласен с чистым кодом. Если число аргументов функции равно нулю, это означает, что функция имеет побочные эффекты и, вероятно, где-то меняет состояние. Хотя я согласен, что хорошим правилом может быть менее 4 аргументов - я бы предпочел иметь функцию с 8 аргументами, которая является статической и не имеет побочных эффектов, чем нестатическая функция с нулевыми аргументами, которая изменяет состояние и имеет побочные эффекты ,
wasatz 23.09.16
4
« В чистом кодексе написано, что„идеальное число аргументов для функции равна нулю“. » В самом деле? Это так неправильно! Идеальное число параметров - один, с возвращаемым значением, которое определено из этого одного параметра. На практике количество параметров не имеет большого значения; важно то, что, когда это возможно, функция должна быть чистой (т. е. она возвращает свое возвращаемое значение только из своих параметров без побочных эффектов).
Дэвид Арно
2
Что ж, позже в книге говорится, что побочные эффекты нежелательны ...
Нил Барнвелл,
2
Возможный дубликат стратегий для переноса параметров
комнат

Ответы:

16

Важно помнить, что это руководящие принципы, а не правила.

Есть случаи, когда метод просто должен принять аргумент. Подумайте, например, о +методе чисел. Или addметод для коллекции.

На самом деле, можно даже утверждать, что то, что означает добавление двух чисел, зависит от контекста, например, в ℤ 3 + 3 == 6, но в ℤ | 5 3 + 3 == 2 , поэтому действительно оператор сложения должен быть методом объекта контекста, который принимает два аргумента вместо метод чисел, который принимает один аргумент.

Аналогично, метод сравнения двух объектов должен быть либо методом одного объекта, принимающего другой в качестве аргумента, либо методом контекста, принимающим два объекта в качестве аргументов, поэтому просто не имеет смысла иметь метод сравнения с менее одного аргумента.

Тем не менее, есть несколько вещей, которые можно сделать, чтобы уменьшить количество аргументов для метода:

  • Сделайте сам метод меньше : может быть, если метод нуждается в таком количестве аргументов, он делает слишком много?
  • Отсутствующая абстракция : если аргументы тесно взаимосвязаны, возможно, они принадлежат друг другу, и есть абстракция, которую вы упускаете? (Пример канонического учебника: вместо двух координат передайте Pointобъект или вместо имени пользователя и электронной почты передайте IdCardобъект.)
  • Состояние объекта : если аргумент нужен нескольким методам, возможно, он должен быть частью состояния объекта. Если это необходимо только некоторым методам, но не другим, возможно, объект делает слишком много и в действительности должен быть двумя объектами.

Одним из способов является извлечение аргументов в новый класс, но это, безусловно, приведет к взрыву классов?

Если в вашей доменной модели много разных видов вещей, то ваш код будет содержать множество разных видов объектов. В этом нет ничего плохого.

И эти классы, скорее всего, будут заканчиваться именами, которые нарушают некоторые правила именования (заканчивающиеся на «Данные» или «Информация» и т. Д.)?

Если вы не можете найти правильное имя, возможно, вы сгруппировали слишком много аргументов или слишком мало. Итак, у вас либо просто фрагмент класса, либо у вас более одного класса.

Другой метод - сделать переменные, используемые несколькими функциями, частной переменной-членом, чтобы избежать их передачи, но это расширяет область действия переменной, возможно, так, что она открыта для функций, которые на самом деле не нуждаются в ней.

Если у вас есть группа методов, все из которых работают с одинаковыми аргументами, и другая группа методов, которые этого не делают, возможно, они принадлежат к разным классам.

Обратите внимание, как часто я использовал слово «возможно»? Вот почему это руководящие принципы, а не правила. Может быть, ваш метод с 4 параметрами отлично подойдет!

Йорг Миттаг
источник
7
@ BrunoSchäpper: Конечно: (1) «Уменьшить сам метод: может быть, если метод требует столько аргументов, он делает слишком много? ». Количество параметров является плохой проверкой этого. Необязательные / логические параметры и множество строк кода являются сильными индикаторами того, что метод делает слишком много. Многие параметры в лучшем случае слабые. (2) « Состояние объекта: если аргумент нужен нескольким методам, возможно, он должен быть частью состояния объекта ». Нет, нет и трижды, нет. Минимизировать состояние объекта; не функциональные параметры. Если возможно, передайте значение всем методам через параметры, чтобы избежать состояния объекта.
Дэвид Арно
Пример, который вы привели для сложения, неверен. addФункция для натуральных чисел и addфункция для кольца целых мод п две разных функции действия на два различных типов. Я тоже не понимаю, что вы подразумеваете под «контекстом».
садовник
Спасибо @DavidArno. 1) согласен, не сильный показатель сам по себе. Но, тем не менее, хороший. Я часто вижу несколько методов с несколькими объектами, переданными вокруг. Нет состояния объекта. Это хорошо, но 2) лучшим вариантом IMHO является рефакторинг этих методов, перемещение неявного состояния в новый класс, который принимает все эти параметры в качестве явных аргументов. В итоге вы получите один открытый метод с нулевым аргументом и множество внутренних методов с нулевым аргументом. Государство не является публичным, глобальным или даже долго сохраняется, но код намного чище.
Бруно Шеппер
6

Обратите внимание, что нулевые аргументы не подразумевают побочные эффекты, потому что ваш объект является неявным аргументом. Посмотрите, например, сколько методов с нулевой аркой имеется в неизменяемом списке Scala .

Одной из полезных техник я называю технику "фокусировки линз". Когда вы фокусируете объектив камеры, легче увидеть истинную точку фокусировки, если вы слишком далеко зашли, а затем верните ее в правильную точку. То же самое относится и к рефакторингу программного обеспечения.

Особенно если вы используете распределенный контроль версий, с изменениями программного обеспечения легко экспериментировать, посмотрите, нравится ли вам их внешний вид, и откатитесь назад, если вы этого не сделаете, но по некоторым причинам люди часто неохотно делают это.

В контексте вашего текущего вопроса это означает написание версий с нулевым или одним аргументом, сначала с несколькими разделенными функциями, а затем сравнительно легко увидеть, какие функции нужно объединить для удобства чтения.

Обратите внимание, что автор также является активным сторонником разработки, основанной на тестировании, которая вначале имеет тенденцию создавать низкоарбитальные функции, потому что вы начинаете с своих тривиальных тестовых случаев.

Карл Билефельдт
источник
1
Как и ваша аналогия с фокусировкой объектива - особенно при рефакторинге, важно использовать широкоугольный объектив вместо крупного. И смотреть на # параметров просто слишком близко
тоф
0

Подход, который просто (и наивно - или я должен даже сказать вслепую ) просто нацелен на уменьшение количества аргументов функций, вероятно, ошибочен. В функциях с большим количеством аргументов нет ничего плохого. Если они требуются логикой, ну, они необходимы ... Длинный список параметров меня совсем не беспокоит - если он правильно отформатирован и закомментирован для удобства чтения.

В случае, когда все или подмножество аргументов принадлежат одному уникальному логическому объекту и обычно передаются группами по всей программе, возможно, имеет смысл сгруппировать их в некоторый контейнер - обычно это структура или другой объект. Типичными примерами могут быть сообщения или события типа данных.

Вы можете легко перестараться с этим подходом - как только вы обнаружите, что упаковка и распаковка вещей в и из таких транспортных контейнеров создает больше накладных расходов, чем улучшает читабельность, вы, вероятно, зашли слишком далеко.

OTOH, большие списки параметров могут быть признаком того, что ваша программа может быть неправильно структурирована - возможно, функция, которая требует такого большого количества параметров , просто пытается сделать слишком много и должна быть разбита на несколько более мелких функций. Я лучше начну здесь, чем беспокоюсь о # параметрах.

tofro
источник
5
Слепое уменьшение количества аргументов, конечно, неправильно. Но я не согласен с тем, что «в функциях с большим количеством аргументов нет ничего плохого». , На мой взгляд, когда вы нажимаете на функцию с большим количеством аргументов, в 99,9% всех случаев есть способ преднамеренно улучшить структуру кода, что (также) уменьшает количество аргументов функции.
Док Браун
@DocBrown Вот почему существует этот последний пункт и рекомендация , чтобы начать там .... И еще один: Вы, наверное , не пытались программы против API MS Windows;)
tofro
«Возможно, функция, которая требует такого большого количества параметров, просто пытается сделать слишком много и должна быть разбита на несколько более мелких функций». Я полностью согласен, хотя на практике вы просто не заканчиваете с другой функцией выше стека, которая вызывает эти несколько меньших функций? Затем вы можете преобразовать их в объект, но у этого объекта будет ctor. Вы могли бы использовать строителя бла-бла-бла. Суть в том, что это бесконечная регрессия - где-то есть ряд значений, которые необходимы программному обеспечению для выполнения своей работы, и они должны каким-то образом получить доступ к этим функциям.
Нил Барнвелл
1
@NeilBarnwell В идеальном случае (стоит рефакторинга) вы можете разделить функцию, которая требует 10 аргументов, на три, которые требуют 3-4 аргумента каждый. В не очень идеальном случае вы получите три функции, которым нужно по 10 аргументов каждая (тогда лучше оставить это в покое). Относительно вашего аргумента стека выше: согласен - может быть так, но не обязательно - аргументы приходят откуда-то, и этот поиск также может быть где-то внутри стека и его просто нужно поместить в нужное место - пробег имеет тенденцию меняться.
tofro
Программная логика никогда не требует более четырех параметров. Только компилятор может.
Доктор
0

Волшебного пути нет: вы должны освоить проблемную область, чтобы найти правильную архитектуру. Это единственный способ рефакторинга: освоение проблемной области. Более четырех параметров - это просто уверенность в том, что ваша текущая архитектура неверна и неверна.

Единственными исключениями являются компиляторы (метапрограммы) и симуляции, где теоретически предел составляет 8, но, вероятно, только 5.

доктор
источник