Это нормально иметь класс только со свойствами для целей рефакторинга?


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

12 79

12 ответов:

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

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

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

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

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

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

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

посмотреть сколько параметров слишком много? еще несколько идей по этому поводу.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

объект параметра-хорошее начало. Но есть еще кое-что, что можно сделать. Рассмотрим следующее (примеры 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

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