Arquitectura de Software 14 Oct 2006 09:56 am

Patrones: Envoltorio

Hace ya tiempo empecé una serie de entradas sobre la reusabilidad en el proceso de elaboración de software. Desde el “Copiar y Pegar”, pasando por middlewares, frameworks y finalmente los Patrones de Diseño. Mi idea es seguir con algunos de los patrones que más estamos utilizando en Osmius utilizando el proyecto como ejemplo de uso.

Envoltorio

Introducción
Uno de los patrones más extendidos en el desarrollo de software que intentas que sea multiplataforma es el Patrón Wrapper Facade, que traduciría como Fachada o Envoltorio. Lo que pretende este patrón es separar diferentes implementaciones de una misma funcionalidad de manera que podamos utilizar esa funcionalidad siempre de la misma forma.

Los sistemas operativos tienen la manía de estar estructurados de formas distintas entre ellos y de proporcionar llamadas al sistema con nombres, parámetros y estructuras diferentes. Suponed que quiero calcular la carga de la cpu; la pregunta es ¿En Linux? ¿En Windows? ¿En qué?. Bueno, la respuesta ideal aquí es “me da igual“. Esto sería porque alguien hubiera desarrollado un envoltorio que que encapsula esas diferencias de forma que tengo un interfaz único (ENVOLTORIOS_VARIOS::dime_la_carga_de_cpu(int carga)) no dependiente de las APIS suministradas en capas más bajas.

Descripción
Es un patrón de diseño para encapsular las funciones y datos proporcionados por APIs existentes no orientadas a objeto, dentro de interfaces de clases orientadas a objeto aportando los beneficios de ser más concisas, robustas, mantenibles y portables.

Contexto
Dos de los tres principales componentes de Osmius como son el Agente Maestro y los Agentes para la monitorización de variables en las diferentes instancias tienen como requisito claro el poder ejecutarse en diferentes plataformas hardware y de sistema operativo. Necesitamos poder distribuir nuestro código y compilarlo (estamos tratando con C++) en por ejemplo, Linux, Windows y Solaris sin modificaciones o con muy poco trabajo extra.

Al ser Osmius una aplicación distribuida en red hace uso de las llamadas del SO para comunicaciones en red a través de sockets y otros mecanismos, de llamadas para el tratamiento y lectura de ficheros, de mecanismos para el lanzamiento, control y terminación de procesos e hilos, y de funciones para demultiplexar la ocurrencia de eventos en conjuntos de uno o varios recursos.
Estas funcionalidades suelen estar disponibles a través de las APIs – normalmente en C no orientado a objeto – de los diferentes SO. Programar usando estas APIs es difícil de aprender, tedioso y poco portable.
ACE proporciona unos interfaces comunes en C para los diferentes SO, que luego encapsula mediante clases C++ aplicando el patrón Wrapper Facade que nos aporta los siguientes beneficios en el caso de Osmius:

  • Sólo aprendemos una vez el interfaz en lugar de con cada SO.
  • Portabilidad garantizada.
  • Detección de posibles problemas con los tipos en tiempo de compilación.
  • Podemos dejar para el tiempo de instalación e incluso de ejecución parámetros de comportamiento de los diferentes mecanismos.

Con este patrón nos evitamos el uso directo de las APIs de bajo nivel de los diferentes sistemas operativos.

Ejemplo de uso
Osmius utiliza las clases envoltorio que proporciona ACE para asegurarse que sus componentes corran en diferentes plataformas.
Por ejemplo al utilizar Osmius la ejecución de procesos en diferentes hilos necesita de mecanismos portables y con el mismo interfaz para garantizar la exclusión mutua en determinadas partes del código y en el acceso a recursos.

La clase que utilizamos es ACE_Thread_Mutex cuyos principales métodos tienen la siguiente interfaz:

int remove (void)
int acquire (void)
Acquire lock ownership (wait on queue if necessary).
int acquire (ACE_Time_Value &tv)
int acquire (ACE_Time_Value *tv)
int tryacquire (void)
int release (void)

La implementación del método acquire() para Solaris es:

int acquire(void) {
return mutex_lock(mutex_);
}

,y existen implementaciones para otras APIS como VxWorks, LynxOS, Windows o hilos POSIX.

El uso dentro del código es:

ACE_Thread_Mutex osmius_mutex;
.....
osmius_mutex.acquire();
.....
funcion_protegida_y_sincronizada();
......
osmius_mutex.release();

Otras clase Wrapper Facade de ACE que usamos en Osmius encapsulan las llamadas para Sockets, gestión de procesos e hilos, operaciones de tiempo, etc.

El uso de este patrón está muy extendido en Osmius y las propias clases de ACE se basan en él para proporcionar servicios de más alto nivel, permitiendo un uso implícito sólo por usar algunos de los frameworks que ACE proporciona.

Comments are closed.