Para un proyecto necesitamos hacer un Middleware. Este Middleware consume servicios del BackOffice del cliente, pero no es solo un catalogo de servicios sino que debe actuar como intermediario entre el cliente y los servicios.
Para implementar esta maravilla se me ocurrió mirar el patrón de diseño Pipe And Filter, después de leer con atención me dije que esto podía hacerse extremadamente simple y quedar muy útil.
Entonces en unas 2,5 horas hice el ejemplo que incluyo en este POST. Este es un ejemplo para mostrarlo a los otros Developer del equipo por lo que deben perdonarme algunas barbaridades en la escritura del código, no es un ejemplo de buenas prácticas de codificación.
Aclarado eso, vamos al grano!!
Descripción del Patrón
Lo primero es entender el patrón Pipe and Filter. Este patrón se refiere a una cadena de filtros por los cuales pasa un mensaje (Contexto), desde el inicio al final. Cada uno de los filtros tiene acceso al contexto tanto de lectura como de escritura. Quien controla el armado y ejecución del Pipe es un Controlador. Este controlador lee de la configuración cuales son los filtros y su orden, los carga y le pasa el contexto al primero. Cuando el primero ejecuta le regresa el control al Controlador para que tome el Contexto y se lo pase al siguiente filtro.
Diagrama 1: Pipe And Filter
Contexto
El contexto es lo que se comparte entre los filtros. Los filtros tienen que compartir un método de ejecución, es este método el que ejecuta el Controlador para que el filtro se active. La siguiente clase es un ejemplo de una implementación de una clase Contexto.
Diagrama 2: Clase Contextooperaciones
EL siguiente código muestra la implementación de de la clase contexto. Este contexto es el que se irá traspasando de filtro en filtro para ser usado en la lógica que implementa cada filtro. Aparte de los dos operadores, que se usaran como argumentos en cada filtro, tiene una lista de respuestas dónde almacenará la respuesta de cada uno de los filtros. Así al terminar la ejecución del Pipe se contará con los resultados de cada filtro en la lista.
Código 1: Clase Contextooperaciones
Filtro
Los filtros componen el Pipe. La idea de los filtros es que expongan un método que los acciones (los ponga a trabajar) y que cuando terminen de ejecutar ese método regresen el Contexto al Controlador del Pipe. En el siguiente diagrama se muestran cuatro filtros los cuales exponen el método interceptar como iniciador del trabajo del filtro.
Diagrama 3: Clases que implementan filtros
El método que los acciona es Interceptar (muy creativo el nombre) el cual recibe el contexto, ejecuta la lógica programada en el filtro y deja el contexto en la propiedad miNuevoContexto para que el controlador del Pipe pueda tomarlo.
El siguiente código muestra la implementación del filtro. Este filtro lo que hace es sumar dos números que lee del contexto y guardar el resultado en una lista de resultados. Esa lista contendrá el resultado de todas las operaciones realizadas en el Pipe, esto es posible porque la lista de resultados está en el contexto y no el filtro.
Controlador
El controlador es el director de orquesta de este patrón, toma desde la configuración cuales son los filtros que debe cargar y en qué orden. Cuando inicia la ejecución utiliza el contexto y se lo entrega al primer filtro ejecutando su método para gatillar la lógica del filtro. En el ejemplo anterior el método Interceptar.
Diagrama 4: Controlador
En el siguiente código se muestra la clase PipeManager, que es el controlador del Pipe. LA instanciarse la clase, se le pasa la configuración XML que contiene los filtros a ser cargados. Una Vez cargados los filtros, el Pipe está listo para ser ejecutado.
Para poner en acción el Pipe es necesario llamar al método Ejecutar pasándolo el contexto inicial como argumento. Opcionalmente hay un parámetro de la ejecución que se llama ExceptionForward. Este segundo parámetro especifica cómo se comporta el Pipe si hay una excepción en alguno de los filtros. Puede comportarse de dos maneras ante una excepción: detenerse o guardar en el log y avanzar.
Código 3: Clase PipeManager
Programa para probar el código
Para probar la implementación hice una aplicación de consola que instancia el controlador pasándole la ruta del archivo XML que contiene la configuración de los filtros. Paso dos, crea el contexto inicial. Luego comienza un loop en el que pide ingresar los dos operadores, los carga en el contexto y ejecuta el Pipe.
Configuracion XML
La configuración XML se muestra en el siguiente archivo XML.
Los códigos de este ejemplo los pueden descargar aquí.
Salu2
Interesante Juan Pablo, lastima que los enlaces estén rotos, saludos
Hola,
Fue un "lapusus" 🙂
ya reparé los Links al código.
Salu2
Hola Juan Pablo, que bueno que estes interesado en patrones en este caso orientados a servicios de mensajería. Se hecha de menos un evento relacionado con patrones, no tando desde el punto de vista de la definición, sino, nombrar los mas interesantes y sus implementaciones. Creo que el usar patrones nos deja hacer un buen uso de la arquitectura.
Hola,
Voy a pasar tú feedback para ver si lo incluyen en las conferencias técnicas de MSDN. A mi me parece muy interesante, pero no sé si es un tema para desarrolladores. Creo que es para arquitectos.
¿Qué opinas?
Salu2
Hola Juan Pablo, estoy de acuerdo contigo que discutir de patrones nos lleva irremediablemente a tocar temas de arquitectura. Pero para mí los Patrones de Diseño (Design Patterns) son la base para la búsqueda de soluciones a problemas comunes en el desarrollo de software. Por lo tanto creo que es responsabilidad del desarrollador conocer los patrones más comúnmente ocupados para así ser un apoyo al arquitecto que este liderando la solución.