Tenemos algunos objetos en nuestro modelo de dominio con lo que se Cómicamente término ofensivamente grandes constructores, tan grande que IntelliSense se da por vencido tratando de mostrar todo a usted ...refactoración grandes constructores
Cue un tipo con 50 o más argumentos, la mayoría de los tipos de valor, algunos tipos de referencia:
public class MyLegacyType
{
public MyLegacyType(int a1, int a2, int a3, ... int a50) // etc
{
}
}
lo voy a decir ahora, sin este tipo no se puede cambiar. El tipo en sí mismo representa lógicamente una entidad, que resulta ser muy pesada. Los usuarios que crean este tipo proporcionan la mayoría de los argumentos de múltiples fuentes, aunque algunos están predeterminados. Quizás haya un patrón para que las fuentes se proporcionen a la construcción en lugar de los resultados.
Sin embargo, lo que puede cambiar es cómo se crea el tipo. Actualmente tenemos secciones de código que sufren de:
- Falta de IntelliSense en el tipo.
- Código feo e ilegible.
- dolores de fusión debido a Connascence of Position.
Una respuesta inmediata es utilizar parámetros opcionales para valores predeterminados y argumentos con nombre para ayudar con la fusión. Hacemos esto hasta cierto punto en otros tipos, funciona bien.
Sin embargo, se siente como si esto estuviera a mitad de camino de la refactorización completa.
La otra solución obvia es reducir los parámetros de constructor con tipos de contenedor que tienen propiedades para lo que solían ser argumentos de constructor. Esto ordena los constructores muy bien, y le permite incrustar valores predeterminados en los contenedores, pero esencialmente mueve el problema a otro tipo y posiblemente equivale al uso de parámetros opcionales/nombrados.
También existe el concepto de constructores Fluent ... tanto en una propiedad (WithIntA
, WithIntB
) como en un tipo de contenedor (WithTheseInts(IntContainer c)
). Personalmente, me gusta este enfoque desde el punto de vista de las llamadas, pero de nuevo en un tipo grande se vuelve prolijo y se siente como si acabara de mover un problema en lugar de resolverlo.
Mi pregunta, si hay una enterrada en este lío, es: ¿son estas tácticas de refactorización viables para el problema? Por favor, responda un poco con alguna experiencia relevante, trampas o críticas. Me estoy inclinando por las cosas Fluent, porque creo que se ve bien y es bastante legible y fácil de combinar.
Siento que me falta el Santo Grial de las refactorizaciones de constructores, así que estoy abierto a sugerencias. Por supuesto, esto también podría ser un efecto secundario desafortunado e inevitable de tener un tipo con muchas propiedades en primer lugar ...
Me gustaría ir con su segundo enfoque (tipos de contenedor que tienen propiedades para lo que solían ser argumentos de constructor) para argumentos de constructor opcionales. Las interfaces fluidas son agradables, pero pueden ser un poco complicadas si tiene que encadenar muchas llamadas de método. IMO –