Recientemente me encontré con la siguiente situación.
class A{
public:
void calculate(T inputs);
}
En primer lugar, A
representa un objeto en el mundo físico, que es un fuerte argumento para no dividir la clase. Ahora, calculate()
resulta ser una función bastante larga y complicada. Percibo tres posibles estructuras para ello:
- escríbalo como un muro de texto - ventajas - toda la información está en un solo lugar
- escribir
private
funciones de utilidad en la clase y usarlas encalculate
el cuerpo de la persona - desventajas - el resto de la clase no sabe / no se preocupa por esos métodos escribe de
calculate
la siguiente manera:void A::calculate(T inputs){ auto lambda1 = () [] {}; auto lambda2 = () [] {}; auto lambda3 = () [] {}; lambda1(inputs.first_logical_chunk); lambda2(inputs.second_logical_chunk); lambda3(inputs.third_logical_chunk); }
¿Se puede considerar esto una buena o mala práctica? ¿Este enfoque revela algún problema? Con todo, ¿debería considerar esto como un buen enfoque cuando me enfrento nuevamente a la misma situación?
EDITAR:
class A{
...
public:
// Reconfiguration of the algorithm.
void set_colour(double colour);
void set_density(double density);
void set_predelay(unsigned long microseconds);
void set_reverb_time(double reverb_time, double room_size);
void set_drywet(double left, double right);
void set_room_size(double value);;
private:
// Sub-model objects.
...
}
Todos esos métodos:
- obtener un valor
- calcular algunos otros valores, sin usar el estado
- llame a algunos de los "objetos de submodelo" para cambiar su estado.
Resulta que, con excepción set_room_size()
, esos métodos simplemente pasan el valor solicitado a los subobjetos. set_room_size()
, por otro lado, hace un par de pantallas de fórmulas oscuras y luego (2) hace media pantalla para llamar a los colocadores de subobjetos para aplicar los diversos resultados obtenidos. Por lo tanto, he separado la función en dos lambdas y las llamo al final de la función. Si hubiera podido dividirlo en partes más lógicas, habría aislado más lambdas.
En cualquier caso, el objetivo de la pregunta actual es determinar si esa forma de pensar debe persistir o, en el mejor de los casos, no agrega valor (legibilidad, facilidad de mantenimiento, capacidad de depuración, etc.).
Firstly, A represents an object in the physical world, which is a strong argument for not splitting the class up.
SeguramenteA
representa datos sobre un objeto que podría existir en el mundo físico. Puede tener una instancia deA
sin el objeto real y un objeto real sin una instancia deA
, por lo que tratarlos como si fueran uno y lo mismo no tiene sentido.calculate()
sabrá sobre esas subfunciones.A
, eso lo lleva un poco al extremo.A
representa un objeto en el mundo físico, que es un fuerte argumento para no dividir la clase". Desafortunadamente, me dijeron esto cuando comencé a programar. Me llevó años darme cuenta de que es un montón de hockey sobre caballos. Es una razón terrible para agrupar cosas. No puedo expresar cuáles son buenas razones para agrupar cosas (al menos para mi satisfacción), pero esa es una que debes descartar ahora mismo. Al final, todo de "buen código" es que funciona correctamente, es relativamente fácil de entender y es relativamente fácil de cambiar (es decir, los cambios no tienen efectos secundarios extraños).Respuestas:
No, este no es generalmente un buen patrón.
Lo que estás haciendo es dividir una función en funciones más pequeñas usando lambda. Sin embargo, hay una herramienta mucho mejor para dividir funciones: funciones.
Las lambdas funcionan, como has visto, pero significan mucho, mucho, mucho, mucho más que simplemente dividir una función en bits locales. Las lambdas hacen:
En el instante en que incorporas lambdas a la mezcla, el siguiente desarrollador que mire el código debe cargar mentalmente de inmediato todas esas reglas en preparación para ver cómo funciona tu código. No saben que no vas a utilizar toda esa funcionalidad. Esto es muy costoso, en comparación con las alternativas.
Es como usar una azada trasera para hacer tu jardinería. Sabes que solo lo estás usando para cavar pequeños agujeros para las flores de este año, pero los vecinos se pondrán nerviosos.
Considere que todo lo que está haciendo es agrupar su código fuente visualmente. Al compilador en realidad no le importa que currieses cosas con lambdas. De hecho, esperaría que el optimizador deshaga inmediatamente todo lo que acaba de hacer cuando se compila. Está atendiendo al siguiente lector (¡Gracias por hacerlo, incluso si no estamos de acuerdo con la metodología! ¡El código se lee con mucha más frecuencia de lo que se escribe!). Todo lo que está haciendo es agrupar la funcionalidad.
// ------------------
entre cada parte.EDITAR: al ver su edición con un código de ejemplo, me inclino hacia la notación de comentarios como la más limpia, con corchetes para imponer los límites que sugieren los comentarios. Sin embargo, si alguna de las funciones fuera reutilizable en otras funciones, recomendaría usar funciones en su lugar
fuente
count++
)calculate()
en{}
bloques y declarando datos compartidos en elcalculate()
ámbito. Pensé que al ver que las lambdas no capturaban, un lector no se vería afectado por el poder de las lambdas.lambda
es injusta o si estás obligando groseramente a las personas a seguir la estricta denotación no es una pregunta fácil de responder. De hecho, puede ser totalmente aceptable para usted usarlo delambda
esa manera en su empresa, y totalmente inaceptable en mi empresa, ¡y ninguno de los dos tiene que estar equivocado!lambda
, como lafor_each
función. En consecuencia, cuando veolambda
que no encaja en uno de esos casos de problemas fáciles de detectar, la primera suposición a la que llego es que probablemente se usará para la programación funcional, porque de lo contrario no era necesario. Para muchos desarrolladores, la programación funcional es una mentalidad completamente diferente de la programación de procedimiento o OO.Creo que hiciste una mala suposición:
No estoy de acuerdo con esto. Por ejemplo, si tuviera una clase que represente un automóvil, definitivamente querría dividirlo, porque seguramente quiero una clase más pequeña que represente los neumáticos.
Debería dividir esta función en funciones privadas más pequeñas. Si realmente parece separado de la otra parte de la clase, entonces eso puede ser una señal de que la clase debería estar separada. Por supuesto, es difícil saberlo sin un ejemplo explícito.
Realmente no veo la ventaja de usar funciones lambda en este caso, porque realmente no hace que el código sea más limpio. Fueron creados para ayudar a la programación de estilo funcional, pero esto no es eso.
Lo que escribió se parece un poco a los objetos de función anidados de estilo Javascript. Lo cual es nuevamente una señal de que están estrechamente unidos. ¿Estás seguro de que no deberías hacer una clase separada para ellos?
En resumen, no creo que este sea un buen patrón.
ACTUALIZAR
Si no ve ninguna forma de encapsular esta funcionalidad en una clase significativa, puede crear funciones auxiliares de ámbito de archivo, que no son miembros de su clase. Esto es C ++ después de todo, el diseño OO no es obligatorio.
fuente
A
(tal vez incluso functor con todos los demás métodos privados)? Clase declarada y definida dentrocalculate()
(esto se parece mucho a mi ejemplo lambda). Como aclaración,calculate()
es uno de una familia de métodos (calculate_1(), calculate_2()
etc.) de los cuales todos son simples, solo este es 2 pantallas de fórmulas.calculate()
mucho más largo que todos los otros métodos?