Каков наилучший способ рефакторинга метода, который имеет слишком много (6+) параметров? - PullRequest
86 голосов
/ 13 января 2009

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

return new Shniz(foo, bar, baz, quux, fred, wilma, barney, dino, donkey)

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

ShnizArgs args = new ShnizArgs(foo, bar, baz, quux, fred, wilma, barney, dino, donkey)
return new Shniz(args);

Так что это не похоже на улучшение. Так каков наилучший подход?

Ответы [ 23 ]

3 голосов
/ 13 января 2009

Вы можете попытаться сгруппировать ваш параметр в кратные значащие структуру / класс (если это возможно).

2 голосов
/ 13 января 2009

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

2 голосов
/ 13 января 2009

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

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

1 голос
/ 13 января 2009

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

1 голос
/ 14 января 2009

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

Предпочитаю маленькие классы / методы большим. Помните принцип единственной ответственности.

1 голос
/ 13 января 2009

Я согласен с подходом перемещения параметров в объект параметра (struct). Вместо того, чтобы просто объединить их все в один объект, проверьте, не используют ли другие функции аналогичные группы параметров. Объект paramater является более ценным, если он используется с несколькими функциями, где ожидается, что этот набор параметров будет последовательно изменяться в этих функциях. Возможно, вы добавили только некоторые параметры в новый объект параметров.

1 голос
/ 13 января 2009

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

1 голос
/ 14 января 2009

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

Другой вариант, который я бы искал при выполнении такого рода рефакторинга, это группы связанных параметров, которые лучше обрабатывать как независимый объект. Используя класс Rectangle из более раннего ответа в качестве примера, конструктор, который принимает параметры для x, y, высоты и ширины, может разложить x и y в объект Point, что позволит вам передать три параметра конструктору Rectangle. Или перейдите немного дальше и укажите два параметра (UpperLeftPoint, LowerRightPoint), но это будет более радикальный рефакторинг.

1 голос
/ 13 января 2009

Как насчет того, чтобы не устанавливать все сразу в конструкторах, а делать это через properties / setters ? Я видел некоторые классы .NET, которые используют этот подход, такие как Process class:

        Process p = new Process();

        p.StartInfo.UseShellExecute = false;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.FileName = "cmd";
        p.StartInfo.Arguments = "/c dir";
        p.Start();
0 голосов
/ 13 января 2009

Это зависит от того, какие у вас есть аргументы, но если они содержат много логических значений / опций, возможно, вы могли бы использовать Flag Enum?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...