Nuestro dominio del conocimiento involucra a personas que caminan sobre una placa de registro de presión con los pies descalzos. Hacemos reconocimiento de imagen que da como resultado objetos de la clase 'Pie', si se reconoce un pie humano en los datos del sensor.
Hay varios cálculos que deben realizarse en los datos del pie.
Ahora, qué API sería mejor:
class Foot : public RecognizedObject {
MaxPressureFrame getMaxPressureFrame();
FootAxis getFootAxis();
AnatomicalZones getAnatomicalZones();
// + similar getters for other calculations
// ...
}
O:
class Foot : public RecognizedObject {
virtual CalculationBase getCalculation(QString aName);
// ...
}
Ahora, hay muchas ventajas y desventajas que se me ocurren, pero realmente no puedo decidir cuáles son las más importantes. Tenga en cuenta que esta es una aplicación de usuario final, no una biblioteca de software que vendemos.
¿Algún consejo?
Algunos profesionales para el primer enfoque podrían ser:
- BESO: todo es muy concreto. La API, pero también la implementación.
- valores de retorno fuertemente tipados.
- heredar de esta clase es infalible. Nada puede ser anulado, solo agregado.
- La API está muy cerrada, no entra nada, nada se puede anular, por lo que menos puede salir mal.
Algunas desventajas:
- El número de captadores crecerá, ya que cada nuevo cálculo que inventamos se agrega a la lista
- Es más probable que la API cambie, y si se introducen cambios de última hora, necesitamos una nueva versión de API, un Foot2.
- en caso de reutilización de la clase en otros proyectos, es posible que no necesitemos todos los cálculos
Algunos profesionales para el segundo enfoque:
- mas flexible
- es menos probable que la API cambie (suponiendo que tengamos la abstracción correcta, si no, cambiar costará más)
Algunas desventajas:
- mecanografiado libremente. Necesita lanzamientos en cada llamada.
- el parámetro de cadena: tengo malos sentimientos al respecto (ramificación en valores de cadena ...)
- No existe un caso / requisito de uso actual que exija una flexibilidad adicional, pero podría existir en el futuro.
- la API impone restricciones: cada cálculo debe derivarse de una clase base. Obtendrá un cálculo mediante este método 1, y pasar parámetros adicionales será imposible, a menos que ideemos una forma aún más dinámica y súper flexible de pasar parámetros que aumente aún más la complejidad.
enum
y encender sus valores. Aún así, creo que la segunda opción es malvada, porque se desvía de KISS.getCalculation()
.Respuestas:
Creo que en primer enfoque valdrá la pena. Las cadenas mágicas pueden crear los siguientes problemas: errores de mecanografía, mal uso, seguridad de tipo de retorno no trivial, falta de finalización del código, código poco claro (¿tenía esta versión esa característica? Supongo que lo descubriremos en tiempo de ejecución). El uso de enumeraciones resolverá algunos de esos problemas, pero veamos los inconvenientes que planteó:
Es cierto que puede ser molesto, sin embargo, mantiene las cosas agradables y estrictas, y le brinda la finalización del código en cualquier parte de su proyecto en cualquier IDE moderno, con buenos comentarios de encabezado que son mucho más útiles que las enumeraciones.
Es cierto, pero en realidad es un gran profesional;) puede definir interfaces para API parciales, y luego no necesita volver a compilar la clase dependiente que no se ve afectada por las API más nuevas (por lo que no es necesario para Foot2). Eso permite un mejor desacoplamiento, la dependencia ahora es de la interfaz y no de la implementación. Además, si cambia una interfaz existente, tendrá un error de compilación en clases dependientes, lo cual es excelente para evitar el código obsoleto.
No veo cómo el uso de cuerdas mágicas o enumeraciones ayudará con eso ... Si entiendo correctamente, o incluye el código en la clase Foot o lo divide en algunas clases más pequeñas, y eso vale para ambas opciones
fuente
IEnumerable<T>.Count
], dicho enfoque puede permitir que el código disfrute de los beneficios de rendimiento de los nuevos características de interfaz cuando se utilizan implementaciones que las admiten, pero siguen siendo compatibles con implementaciones antiguasRecomendaría la opción 3: dejar en claro que los cálculos no son una parte intrínseca de la abstracción de a
Foot
, sino que funcionan con ella. Luego puede dividirFoot
y los cálculos en clases separadas, así:De esta manera, aún tiene un tipeo fuerte de su cálculo, y puede agregar nuevos sin afectar el código existente (a menos que haya cometido un error grave en la cantidad de información expuesta por
Foot
).fuente