Arquitectura modular para procesamiento de tuberías

8

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?

anjruu
fuente
1
¿Está seguro de que no desea utilizar un lenguaje de la familia Lisp para este tipo de proyecto?
Trabajo
Oh, ciertamente quiero usar un lenguaje de la familia Lisp para este proyecto, trágicamente, estoy agregando funcionalidad a una biblioteca de imágenes C ++ existente.
anjruu

Respuestas:

2

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.

Steven Jeuris
fuente
2

Tal vez cree una lista de functores en una fábrica, que implementen las etapas. Pseudocódigo:

functorFactory() {
  return [ foo(), bar(), baz() ]
}

Los usuarios podrían reimplementar la fábrica o simplemente manipular la lista de functores. Pseudocódigo

myFactory() {
  return [ foo(), myBar() ]
}

o

myFactory() {
  return functorFactory()[2] = myBar()
}

Cuando finalice la configuración, puede llamar a cada functor utilizando el resultado del último.

LennyProgrammers
fuente
+1: esto proporciona la máxima flexibilidad, ya que el usuario puede agregar / eliminar pasos si así lo desea.
Matthieu M.
1
Eso se ve muy bien, pero ¿cómo implementaría esto en C ++? No podría tener una matriz de punteros de función, ya que cada puntero de función tendría un tipo diferente si las funciones devolvieran cosas diferentes, y las matrices solo pueden contener objetos del mismo tipo. ¡Gracias!
anjruu
0

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.

Zachary K
fuente
0

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.

Paul Nathan
fuente