У меня есть метод, который принимает 30 параметров. Я взял параметры и поместил их в один класс, чтобы я мог просто передать один параметр (класс) в метод. Совершенно нормально в случае рефакторинга передать объект, который инкапсулирует все параметры, даже если это все, что он содержит.
c#
oop
refactoring
Xaisoft
источник
источник
Ответы:
Это отличная идея. Обычно так заключаются контракты данных, например, в WCF.
Одно из преимуществ этой модели состоит в том, что если вы добавляете новый параметр, потребителю класса не нужно изменять только для добавления параметра.
Как упоминает Дэвид Хеффернан, это может помочь самостоятельно задокументировать код:
FrobRequest frobRequest = new FrobRequest { FrobTarget = "Joe", Url = new Uri("http://example.com"), Count = 42, }; FrobResult frobResult = Frob(frobRequest);
источник
Хотя другие ответы здесь правильно указывают на то, что передача экземпляра класса лучше, чем передача 30 параметров, имейте в виду, что большое количество параметров может быть симптомом основной проблемы.
Например, количество параметров у статических методов многократно увеличивается, потому что они всегда должны были быть методами экземпляра, а вы передаете много информации, которую легче поддерживать в экземпляре этого класса.
Как вариант, ищите способы сгруппировать параметры в объекты более высокого уровня абстракции. Сброс кучи несвязанных параметров в один класс - последнее средство ИМО.
См. Сколько параметров слишком много? для получения дополнительных идей по этому поводу.
источник
Хорошее начало. Но теперь, когда у вас есть этот новый класс, подумайте о том, чтобы вывернуть свой код наизнанку. Переместите метод, который принимает этот класс в качестве параметра, в ваш новый класс (конечно, передав экземпляр исходного класса в качестве параметра). Теперь у вас есть большой метод, единственный в классе, и его будет легче разделить на более мелкие, более управляемые и тестируемые методы. Некоторые из этих методов могут вернуться в исходный класс, но значительная часть, вероятно, останется в вашем новом классе. Вы перешли от « Ввести объект параметра» к « Заменить метод» на объект-метод .
Наличие метода с тридцатью параметрами - довольно сильный признак того, что метод слишком длинный и слишком сложный. Слишком сложно отлаживать, слишком сложно тестировать. Так что вы должны что-то с этим сделать, и Introduce Parameter Object - отличное место для начала.
источник
Хотя рефакторинг объекта параметров сам по себе не является плохой идеей, его не следует использовать, чтобы скрыть проблему, заключающуюся в том, что класс, которому требуется 30 фрагментов данных, предоставленных из других источников, все еще может быть чем-то вроде запаха кода. Рефакторинг объекта «Введение параметров», вероятно, следует рассматривать как этап в более широком процессе рефакторинга, а не как его завершение.
Одна из проблем, которую он на самом деле не решает, - это Feature Envy. Не указывает ли тот факт, что класс, которому передается объект параметров, так интересны данные другого класса, на то, что, возможно, методы, которые работают с этими данными, должны быть перемещены туда, где они находятся? Действительно лучше идентифицировать кластеры методов и данных, которые принадлежат друг другу, и группировать их в классы, тем самым увеличивая инкапсуляцию и делая ваш код более гибким.
После нескольких итераций разделения поведения и данных, с которыми оно работает, на отдельные блоки, вы должны обнаружить, что у вас больше нет классов с огромным количеством зависимостей, что всегда является лучшим конечным результатом, потому что это сделает ваш код более гибким.
источник
Это отличная идея и очень распространенное решение проблемы. Методы с более чем 2 или 3 параметрами становятся экспоненциально сложнее и труднее для понимания.
Инкапсуляция всего этого в одном классе делает код более понятным. Поскольку у ваших свойств есть имена, вы можете написать самодокументированный код следующим образом:
params.height = 42; params.width = 666; obj.doSomething(params);
Естественно, когда у вас много параметров, альтернатива, основанная на позиционной идентификации, просто ужасна.
Еще одно преимущество заключается в том, что добавление дополнительных параметров к контракту интерфейса может быть выполнено без принудительных изменений на всех сайтах вызова. Однако это не всегда так тривиально, как кажется. Если разные сайты вызовов требуют разных значений для нового параметра, то их труднее выследить, чем при использовании подхода на основе параметров. В подходе, основанном на параметрах, добавление нового параметра заставляет изменение на каждом сайте вызова предоставить новый параметр, и вы можете позволить компилятору выполнить работу по их поиску.
источник
Мартин Фаулер в своей книге « Рефакторинг» называет этот объект « ввести параметр» . С такой цитатой мало кто назовет это плохой идеей.
источник
30 параметров - это бардак. Я думаю, что лучше иметь класс со свойствами. Вы даже можете создать несколько «классов параметров» для групп параметров, которые входят в одну категорию.
источник
Вы также можете рассмотреть возможность использования структуры вместо класса.
Но то, что вы пытаетесь сделать, очень распространено и является отличной идеей!
источник
Может быть разумным использовать класс Plain Old Data независимо от того, проводите ли вы рефакторинг или нет. Мне любопытно, почему вы подумали, что это может быть не так.
источник
Может быть, необязательные и именованные параметры C # 4.0 станут хорошей альтернативой этому?
В любом случае, метод, который вы описываете, также может быть полезен для абстрагирования поведения программ. Например, у вас может быть одна стандартная
SaveImage(ImageSaveParameters saveParams)
функция в интерфейсе, котораяImageSaveParameters
также является интерфейсом и может иметь дополнительные параметры в зависимости от формата изображения. НапримерJpegSaveParameters
естьQuality
-свойство покаPngSaveParameters
имеетBitDepth
-свойство.Вот как это делает диалог сохранения в Paint.NET, так что это очень реальный пример.
источник
Как указывалось ранее: это правильный шаг, но примите во внимание и следующее:
источник
Здесь так много отличных ответов. Я хочу добавить свои два цента.
Объект-параметр - хорошее начало. Но можно сделать еще больше. Рассмотрим следующее (примеры рубинов):
/ 1 / Вместо того, чтобы просто группировать все параметры, посмотрите, может ли быть значимая группировка параметров. Вам может понадобиться более одного объекта параметра.
def display_line(startPoint, endPoint, option1, option2)
может стать
def display_line(line, display_options)
/ 2 / Объект параметра может иметь меньшее количество свойств, чем исходное количество параметров.
может стать
def double_click?(first_click_info, second_click_info) # MouseClickInfo being the parameter object type # having cursor_location and control_at_click as properties
Такое использование поможет вам обнаружить возможности добавления значимого поведения к этим объектам параметров. Вы обнаружите, что они избавляются от своего первоначального запаха Data Class раньше, к вашему удобству. : -)
источник