Хорошо ли иметь класс с просто свойствами для рефакторинга?

У меня есть метод, который принимает 30 параметров. Я взял параметры и поместил их в один класс, чтобы я мог просто передать один параметр (класс) в метод. Это прекрасно, если рефакторинг передается в объект, который инкапсулирует все параметры, даже если это все, что он содержит.

Ответ 1

Это отличная идея. Обычно, как контракты данных выполняются в WCF, например.

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

Как упоминает Дэвид Хеффернан, он может самостоятельно документировать код:

FrobRequest frobRequest = new FrobRequest
{
    FrobTarget = "Joe",
    Url = new Uri("http://example.com"),
    Count = 42,
};
FrobResult frobResult = Frob(frobRequest);

Ответ 2

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

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

В качестве альтернативы, найдите способы группировки параметров в объекты с более высоким уровнем абстракции. Сбрасывание пучка несвязанных параметров в один класс является последней мерой IMO.

См. Сколько параметров слишком много? для получения дополнительных идей по этому вопросу.

Ответ 3

Это хорошее начало. Но теперь, когда у вас есть этот новый класс, подумайте о том, чтобы превратить ваш код в наизнанку. Переместите метод, который переносит этот класс в качестве параметра в ваш новый класс (конечно, передавая экземпляр исходного класса в качестве параметра). Теперь у вас есть большой метод, один в классе, и будет проще дразнить его на более мелкие, более управляемые, тестируемые методы. Некоторые из этих методов могут вернуться к первоначальному классу, но справедливый кусок, вероятно, останется в вашем новом классе. Вы перешли за пределы Ввести объект параметров на Заменить метод с помощью объекта метода.

Наличие метода с тридцатью параметрами является довольно сильным признаком того, что метод слишком длинный и слишком сложный. Слишком сложно отлаживать, слишком сложно тестировать. Итак, вы должны что-то сделать, и введение объекта Parameter - прекрасное место для начала.

Ответ 4

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

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

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

Ответ 5

Это отличная идея и очень общее решение проблемы. Методы с более чем 2 или 3 параметрами экспоненциально сложнее и труднее понять.

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

params.height = 42;
params.width = 666;
obj.doSomething(params);

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

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

Ответ 6

Мартин Фаулер называет это Ввести объект параметров в своей книге Рефакторинг. С этой ссылкой немногие назвали бы ее плохими.

Ответ 7

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

Ответ 8

Вы также можете рассмотреть возможность использования структуры вместо класса.

Но то, что вы пытаетесь сделать, очень распространено и отличная идея!

Ответ 9

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

Ответ 10

Возможно, альтернативными и названными параметрами С# 4.0 являются хорошая альтернатива этому?

В любом случае метод, который вы описываете, также может быть полезен для абстрагирования поведения программ. Например, у вас может быть одна стандартная SaveImage(ImageSaveParameters saveParams) -функция в интерфейсе, где ImageSaveParameters также является интерфейсом и может иметь дополнительные параметры в зависимости от формата изображения. Например, JpegSaveParameters имеет Quality -property, а PngSaveParameters имеет BitDepth -property.

Таким образом, сохранение save-dialog в Paint.NET делает это, так что это очень реальный пример жизни.

Ответ 11

Как указано выше: это правильный шаг, но также рассмотрите следующие пункты:

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

Ответ 12

Здесь так много замечательных ответов. Я хотел бы добавить мои два цента.

Объект параметров - хорошее начало. Но есть еще что можно сделать. Рассмотрим следующие (примеры ruby):

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

def display_line(startPoint, endPoint, option1, option2)

может стать

def display_line(line, display_options)

/2/Объект параметра может иметь меньшее количество свойств, чем исходное количество параметров.

def double_click?(cursor_location1, control1, cursor_location2, control2)

может стать

def double_click?(first_click_info, second_click_info) 
                       # MouseClickInfo being the parameter object type 
                       # having cursor_location and control_at_click as properties

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