Tengo un método que toma 30 parámetros. Tomé los parámetros y los puse en una clase, para poder pasar un parámetro (la clase) al método. ¿Está perfectamente bien en el caso de la refactorización pasar un objeto que encapsule todos los parámetros incluso si eso es todo lo que contiene?
c#
oop
refactoring
Xaisoft
fuente
fuente
Respuestas:
Esa es una gran idea. Por lo general, es cómo se realizan los contratos de datos en WCF, por ejemplo.
Una ventaja de este modelo es que si agrega un nuevo parámetro, el consumidor de la clase no necesita cambiar solo para agregar el parámetro.
Como menciona David Heffernan, puede ayudar a autodocumentar el código:
FrobRequest frobRequest = new FrobRequest { FrobTarget = "Joe", Url = new Uri("http://example.com"), Count = 42, }; FrobResult frobResult = Frob(frobRequest);
fuente
Si bien otras respuestas aquí señalan correctamente que pasar una instancia de una clase es mejor que pasar 30 parámetros, tenga en cuenta que una gran cantidad de parámetros puede ser un síntoma de un problema subyacente.
Por ejemplo, muchas veces los métodos estáticos aumentan en su número de parámetros, porque deberían haber sido métodos de instancia todo el tiempo, y estás pasando mucha información que podría mantenerse más fácilmente en una instancia de esa clase.
Alternativamente, busque formas de agrupar los parámetros en objetos de un nivel de abstracción superior. Volcar un montón de parámetros no relacionados en una sola clase es un último recurso en mi opinión.
Consulte ¿Cuántos parámetros son demasiados? para obtener más ideas sobre esto.
fuente
Es un buen comienzo. Pero ahora que tiene esa nueva clase, considere darle la vuelta al código. Mueva el método que toma esa clase como parámetro a su nueva clase (por supuesto, pasando una instancia de la clase original como parámetro). Ahora tiene un método grande, solo en una clase, y será más fácil dividirlo en métodos más pequeños, manejables y probables. Algunos de esos métodos pueden regresar a la clase original, pero una buena parte probablemente permanecerá en su nueva clase. Ha pasado de Introducir objeto de parámetro a Reemplazar método con Objeto de método .
Tener un método con treinta parámetros es una señal bastante fuerte de que el método es demasiado largo y complicado. Demasiado difícil de depurar, demasiado difícil de probar. Por lo tanto, debe hacer algo al respecto, y Introducir objeto de parámetro es un buen lugar para comenzar.
fuente
Si bien la refactorización a un objeto de parámetro no es en sí misma una mala idea, no debería usarse para ocultar el problema de que una clase que necesita 30 piezas de datos provistas de otra parte aún podría ser una especie de olor a código. La refactorización de Introducir objeto de parámetro probablemente debería considerarse como un paso en el camino de un proceso de refactorización más amplio en lugar de como el final de ese procedimiento.
Una de las preocupaciones que realmente no aborda es la de Feature Envy. ¿El hecho de que la clase a la que se le pasa el objeto de parámetro esté tan interesada en los datos de otra clase no indica que tal vez los métodos que operan sobre esos datos deban trasladarse al lugar donde residen los datos? Es realmente mejor identificar grupos de métodos y datos que pertenecen juntos y agruparlos en clases, aumentando así la encapsulación y haciendo que su código sea más flexible.
Después de varias iteraciones de dividir el comportamiento y los datos con los que opera en unidades separadas, debería encontrar que ya no tiene clases con un número enorme de dependencias, lo que siempre es un mejor resultado final porque hará que su código sea más flexible.
fuente
Esa es una idea excelente y una solución muy común al problema. Los métodos con más de 2 o 3 parámetros se vuelven cada vez más difíciles de entender.
Encapsular todo esto en una sola clase hace que el código sea mucho más claro. Debido a que sus propiedades tienen nombres, puede escribir código autodocumentado como este:
params.height = 42; params.width = 666; obj.doSomething(params);
Naturalmente, cuando tienes muchos parámetros, la alternativa basada en la identificación posicional es simplemente horrible.
Otro beneficio más es que se pueden agregar parámetros adicionales al contrato de interfaz sin forzar cambios en todos los sitios de llamadas. Sin embargo, esto no siempre es tan trivial como parece. Si diferentes sitios de llamadas requieren valores diferentes para el nuevo parámetro, entonces es más difícil buscarlos que con el enfoque basado en parámetros. En el enfoque basado en parámetros, agregar un nuevo parámetro fuerza un cambio en cada sitio de llamada para proporcionar el nuevo parámetro y puede dejar que el compilador haga el trabajo de encontrarlos todos.
fuente
Martin Fowler llama a este objeto Introducir parámetro en su libro Refactorización . Con esa cita, pocos lo llamarían una mala idea.
fuente
30 parámetros es un desastre. Creo que es mucho más bonito tener una clase con las propiedades. Incluso podría crear varias "clases de parámetros" para grupos de parámetros que encajen en la misma categoría.
fuente
También podría considerar usar una estructura en lugar de una clase.
¡Pero lo que intentas hacer es muy común y una gran idea!
fuente
Puede ser razonable usar una clase Plain Old Data ya sea que esté refactorizando o no. Tengo curiosidad por saber por qué pensaste que podría no ser así.
fuente
¿Quizás los parámetros opcionales y con nombre de C # 4.0 sean una buena alternativa a esto?
De todos modos, el método que está describiendo también puede ser bueno para abstraer el comportamiento del programa. Por ejemplo, podría tener una función estándar
SaveImage(ImageSaveParameters saveParams)
en una interfaz dondeImageSaveParameters
también hay una interfaz y puede tener parámetros adicionales dependiendo del formato de imagen. Por ejemplo,JpegSaveParameters
tiene unaQuality
propiedad mientras quePngSaveParameters
tiene unaBitDepth
propiedad.Así es como lo hace el cuadro de diálogo guardar guardar en Paint.NET, por lo que es un ejemplo muy real.
fuente
Como se indicó anteriormente: es el paso correcto a seguir, pero considere también lo siguiente:
fuente
Tantas grandes respuestas aquí. Me gustaría agregar mis dos centavos.
El objeto de parámetro es un buen comienzo. Pero aún se puede hacer más. Considere lo siguiente (ejemplos de ruby):
/ 1 / En lugar de simplemente agrupar todos los parámetros, vea si puede haber una agrupación significativa de parámetros. Es posible que necesite más de un objeto de parámetro.
def display_line(startPoint, endPoint, option1, option2)
podría convertirse
def display_line(line, display_options)
/ 2 / El objeto de parámetro puede tener un número menor de propiedades que el número original de parámetros.
podría convertirse
def double_click?(first_click_info, second_click_info) # MouseClickInfo being the parameter object type # having cursor_location and control_at_click as properties
Dichos usos le ayudarán a descubrir posibilidades de agregar un comportamiento significativo a estos objetos de parámetros. Descubrirá que se deshacen de su olor inicial de clase de datos antes para su comodidad. : -)
fuente