Desde una perspectiva de principios SÓLIDOS , la respuesta de jgauffin tiene sentido. Sin embargo, no debe olvidarse de los principios generales de diseño, por ejemplo, la ocultación de información .
Veo varios problemas con el enfoque dado:
- Como usted mismo señaló, la gente no espera usar la palabra clave "nueva", cuando el objeto creado no administra ningún estado . Su diseño refleja su intención. Las personas que usan su clase pueden confundirse sobre el estado que administra y si las llamadas posteriores al método pueden dar lugar a un comportamiento diferente.
- Desde la perspectiva de la persona que usa la clase, el estado interno está bien oculto, pero cuando quieres hacer modificaciones a la clase o simplemente entenderlo, estás haciendo las cosas más complejas. Ya he escrito mucho sobre los problemas que veo con los métodos de división solo para hacerlos más pequeños , especialmente cuando se mueve el estado al alcance de la clase. ¡Está modificando la forma en que se debe usar su API solo para tener funciones más pequeñas! Eso en mi opinión definitivamente lo lleva demasiado lejos.
Algunas referencias relacionadas
Posiblemente, un argumento principal radica en qué tan lejos se puede extender el Principio de Responsabilidad Única . "Si lo llevas a ese extremo y construyes clases que tienen una razón para existir, puedes terminar con un solo método por clase. Esto causaría una gran expansión de clases incluso para los procesos más simples, causando que el sistema sea difícil de entender y difícil de cambiar ".
Otra referencia relevante relacionada con este tema: "Divida sus programas en métodos que realicen una tarea identificable. Mantenga todas las operaciones en un método al mismo nivel de abstracción ". - Kent Beck Key aquí es "el mismo nivel de abstracción". Eso no significa "una cosa", ya que a menudo se interpreta. Este nivel de abstracción depende completamente del contexto para el que está diseñando.
Entonces, ¿cuál es el enfoque adecuado?
Sin conocer su caso de uso concreto, es difícil saberlo. Hay un escenario en el que a veces (no muy a menudo) uso un enfoque similar. Cuando quiero procesar un conjunto de datos, sin querer que esta funcionalidad esté disponible para todo el alcance de la clase. Escribí una publicación de blog sobre esto, cómo lambdas puede mejorar aún más la encapsulación . Yo también empecé a una pregunta sobre el tema aquí en Los programadores . El siguiente es un último ejemplo de dónde usé esta técnica.
new TupleList<Key, int>
{
{ Key.NumPad1, 1 },
...
{ Key.NumPad3, 16 },
{ Key.NumPad4, 17 },
}
.ForEach( t =>
{
var trigger = new IC.Trigger.EventTrigger(
new KeyInputCondition( t.Item1, KeyInputCondition.KeyState.Down ) );
trigger.ConditionsMet += () => AddMarker( t.Item2 );
_inputController.AddTrigger( trigger );
} );
Dado que el código muy 'local' dentro del ForEachno se reutiliza en ningún otro lugar, simplemente puedo mantenerlo en la ubicación exacta donde es relevante. Esbozar el código de tal manera que el código que se basa el uno en el otro está fuertemente agrupado lo hace más legible en mi opinión.
Posibles alternativas
- En C #, podría usar métodos de extensión en su lugar. Así que opera el argumento directamente que pasas a este método de 'una cosa'.
- Vea si esta función en realidad no pertenece a otra clase.
- Conviértalo en una función estática en una clase estática . Este es probablemente el enfoque más apropiado, como también se refleja en las API generales a las que se refirió.
bool arrayContainsSomestring = new List<string>(stringArray).Contains("somestring");cuando todo lo que me importaba era esa información en particular y los métodos de extensión LINQ no están disponibles. Funciona bien y se ajusta dentro de unaif()condición sin necesidad de saltar a través de aros. Por supuesto, desea un lenguaje recolectado de basura si está escribiendo código como ese.