Estoy tratando de diseñar la arquitectura de un sistema que implementaré en C ++, y me preguntaba si la gente podría pensar en un buen enfoque o criticar el enfoque que he diseñado hasta ahora.
En primer lugar, el problema general es una tubería de procesamiento de imágenes. Contiene varias etapas, y el objetivo es diseñar una solución altamente modular, de modo que cualquiera de las etapas pueda intercambiarse fácilmente y reemplazarse con un código personalizado (para que el usuario pueda aumentar la velocidad si lo sabe). que cierta etapa está limitada de cierta manera en su problema).
El pensamiento actual es algo como esto:
struct output; /*Contains the output values from the pipeline.*/
class input_routines{
public:
virtual foo stage1(...){...}
virtual bar stage2(...){...}
virtual qux stage3(...){...}
...
}
output pipeline(input_routines stages);
Esto permitiría a las personas subclasificar input_routines y anular la etapa que quisieran. Dicho esto, he trabajado en sistemas como este antes, y creo que las subclases y las cosas predeterminadas tienden a complicarse, y pueden ser difíciles de usar, por lo que no me marea escribir una. También estaba pensando en un enfoque más STLish, donde las diferentes etapas (hay 6 o 7) serían parámetros de plantilla predeterminados.
¿Alguien puede ofrecer una crítica del patrón anterior, pensamientos sobre el enfoque de la plantilla o cualquier otra arquitectura que se le ocurra?
fuente
Respuestas:
El diseño depende en gran medida de lo que realmente hacen las diferentes etapas. Principalmente prefiero las funciones virtuales puras sobre las funciones virtuales no puras (clases abstractas).
Las etapas comunes se pueden agrupar en subclases abstractas. Al derivar de la clase abstracta principal, aún puede ajustar cada etapa, pero al derivar de una subclase puede reutilizar el comportamiento existente que ya está escrito. Tiende a ser menos complicado, como mencionas para los métodos virtuales.
Si las diferentes etapas también pueden existir por sí mismas (fuera de toda la tubería), también considere escribir clases para separar este comportamiento.
fuente
Tal vez cree una lista de functores en una fábrica, que implementen las etapas. Pseudocódigo:
Los usuarios podrían reimplementar la fábrica o simplemente manipular la lista de functores. Pseudocódigo
o
Cuando finalice la configuración, puede llamar a cada functor utilizando el resultado del último.
fuente
Eche un vistazo a las mónadas implementadas en Haskell, que pueden darle una buena idea sobre cómo configurar las cosas. Haskell hace este tipo de cosas realmente bien.
fuente
Definiría un tipo intermedio. Todas las imágenes se convertirían a este formato; cada etapa tomaría un intermedio y devolvería un intermedio, no el mismo, uno nuevo.
Una etapa sería esta:
Intermediate DoSomething(const Intermediate &i);
Por lo general, evito las soluciones basadas en herencia en general, a menos que sean un mapa bastante obvio sobre el problema, por ejemplo, objetos en un mundo 3D.
fuente