Descripción y utilización práctica del patrón de diseño Callback Distribuido en aplicaciones distribuidas con CORBA (LSI-2000-04)
Full text
' (6&5,3&,Ï1<87,/,=$&,Ï135È&7,&$'(/3$75Ï1'(',6(f2 & $//%$&. ' ,675,%8,'2(1$3/,&$&,21(6',675,%8,'$6&21 &25%$ -RDTXtQ3HxD)UDQFLVFR/HDO\5DIDHO&RUFKXHOR ,QIRUPH7pFQLFR 'SWR/HQJXDMHV\6LVWHPDV,QIRUPiWLFRVGHOD8QLYHUVLGDGGH6HYLOOD $YGDGHOD5HLQD0HUFHGHVVQ6HYLOOD (PDLOMSHQD#OVLXVHV
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ ,1',&( ,1752'8&&,Ï1 )81'$0(1726'(&25%$ 02'(/2(175(6&$3$6 2.1.CAPA CLIENTE......................................................................................................7 2.2. CAPA LÓGICA O AGENTE......................................................................................7 2.3. CAPA SERVIDOR ..................................................................................................8 2.4. INTERCONEXIÓN ENTRE CAPAS.............................................................................8 (QODFH$JHQWH6HUYLGRU (QODFH&OLHQWH$JHQWH 3$7521'(',6(f2&$//%$&.',675,%8,'23$5$$3/,&$&,21(6 &25%$ 3.1. INTRODUCCIÓN..................................................................................................10 3.2. DESCRIPCIÓN DEL PATRÓN.................................................................................10 ,QWHQFLyQ 0RWLYDFLyQ $SOLFDELOLGDG &RQVHFXHQFLDVYHQWDMDVHLQFRQYHQLHQWHV ,PSOHPHQWDFLyQ (-(03/2'($3/,&$&,Ï1 4.1. INTRODUCCIÓN..................................................................................................15 4.2. DESCRIPCIÓN DE LA APLICACIÓN A DESARROLLAR..............................................15 4.3. MODELADO DE LA APLICACIÓN. .........................................................................18 4.4. UTILIZACIÓN DEL PATRÓN DE DISEÑO CALLBACK DISTRIBUÍDO EN LA APLICACIÓN. ................................................................................................................................21 )81&,21$0,(172(,167$/$&,Ï1 5.1. FUNCIONAMIENTO. ............................................................................................26 352%/(0$6<&21&/86,21(6 6.1. PROBLEMAS.......................................................................................................30 6.2. CONCLUSIONES..................................................................................................30 %,%/,2*5$)Ë$
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ ,1752'8&&,Ï1 El propósito de este documento es mostrar tanto la estructura como la utilización práctica del patrón de diseño &DOOEDFN 'LVWULEXLGR para aplicaciones CORBA. Un patrón de diseño es una descripción de clases y objetos comunicándose entre sí adaptada para resolver un problema de diseño general en un contexto particular. En este caso, el contexto que se propone es una aplicación en tres capas con funcionamiento síncrono que será modificada para que se comporte de manera asíncrona utilizando dicho patrón. Para poder comprender de manera global la aplicación propuesta es necesario conocer algunos conceptos como son CORBA y el modelo en tres capas. CORBA es un middleware que permite conectar clientes y servidores heterogéneos tanto en el lenguaje de programación como en la plataforma de ejecución de una manera transparente. Por otro lado, la arquitectura en tres capas, que se corresponde al patrón arquitectónico nivel, realiza una división de la aplicación en capas para aislar en cada una de ellas aquellos elementos del sistema que están relacionados entre sí a un alto nivel de abstracción. Las características de una capa concreta no dependen en ningún aspecto del resto de las capas, comportándose cada una de ellas como un elemento independiente del resto. Este documento se dividirá en 6 capítulos. En el FDStWXORSULPHUR se describirá, en términos generales, el estándar CORBA. En el FDStWXOR VHJXQGR se introducirá el concepto de arquitectura en tres capas. En el FDStWXOR WHUFHUR se describirá el patrón de diseño FDOOEDFN GLVWULEXLGR detallando sus características, ventajas, inconvenientes e implementación. Seguidamente, en el FDStWXOR FXDUWR se describirá un ejemplo práctico de aplicación al que se le aplicará el patrón FDOOEDFN . En el FDStWXORTXLQWR se mostrará el funcionamiento de la aplicación y se destacarán la mejoras conseguidas con la aplicación del patrón. Y por ultimo, en el FDStWXORVH[WR se hará un recorrido por los problemas más importantes encontrados y las conclusiones inferidas de la realización de este documento.
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ )81'$0(1726'(&25%$ CORBA es una norma, no un producto, que se encarga de especificar la interoperabilidad entre objetos en un entorno distribuido heterogéneo de manera transparente. CORBA fue impulsada por la OMG (Object Management Group) en 1990. Se propuso una arquitectura basada en componentes con capacidad de interoperabilidad (llevan integrada la conectividad de red) con independencia de la localización. Finalmente, en 1992 la OMG definió el primer ORB (Object Request Broker). En definitiva, CORBA es un middleware que permite conectar clientes y servidores heterogéneos tanto en el lenguaje de programación como en la plataforma de ejecución. Esto se consigue de forma transparente para los clientes y servidores. Los clientes simplemente invocan un método de un objeto servidor y no tienen que preocuparse de la localización de dicho objeto. Además, la petición se realiza en el lenguaje de programación en que está implementado el cliente aunque el servidor esté realizado en otro distinto. El encargado de la traducción y transporte de la llamada es el ORB (Object Request Broker), una pieza fundamental de la arquitectura de CORBA. Figura 1. El ORB de CORBA El ORB es un "bus de objetos" que permite a los objetos hacer llamadas a otros de forma transparente, independientemente de su localización, del sistema operativo donde se ejecuten y del lenguaje en el que están implementados. Esto se consigue gracias al lenguaje IDL (Interface Definition Language). Mediante IDL se especifican interfaces, consistentes en conjuntos de operaciones que los objetos que actúan como servidores proporcionan a los clientes. Usando un compilador de IDL, se genera el código necesario en un
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ lenguaje de programación determinado para el lado cliente (los stubs) y el lado servidor (skeletons). En el lado cliente, el código generado se usa en la implementación del cliente como cualquier librería convencional, que hace ver al cliente el objeto(s) servidor y sus servicios. En la parte servidora se genera código que recibe las peticiones locales o vía red de los clientes y se encarga de llamar a las funciones del servidor que proporciona la interfaz IDL, cuyas cabeceras/esqueletos también se han generado, debiendo ser implementado por el programador el código de los métodos existentes en la interfaz. Este esquema es similar al de las clásicas Remote Procedure Calls (RPCs).
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ 02'(/2(175(6&$3$6 El modelo en tres capas surge como una mejora sobre la arquitectura clásica en dos capas. Esta basado en la inclusión de una nueva capa o nivel de abstracción en la que se aísla la lógica de administración del sistema del resto de bloques. El objetivo de esta división es conseguir una mayor independencia entre los elementos que forman parte del sistema, haciendo que cada uno de ellos se comporte de manera transparente y que pueda cambiar sin afectar a los demás. El objetivo es que cada capa se vea como un elemento independiente del resto de capas. Una de las consecuencias de esta mejora es que la parte cliente puede quedar reducida a una simple interfaz gráfica y la parte servidora a la base de datos y el DBMS. La lógica de negocio entre la parte cliente y la servidor se centralizará en la nueva capa insertada. Gracias a la versatilidad que proporciona este modelo se podrán utilizar las capas como piezas de un mecano, tomando el número de ellas que sean necesarias y adaptando así el resultado final a distintas necesidades. Además, se podrá reutilizar cada parte tantas veces como sea necesario. Figura 2. Modelo en tres capas. A continuación se describirá cada una de las capas que constituyen el modelo.
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ &DSD&OLHQWH La primera capa que se observa en la figura anterior es el cliente. En ella estará implementado el cliente en forma de interfaz gráfica con la que interactuará el usuario. La interfaz permite introducir datos a procesar por la aplicación y muestra los datos que genera como resultado de dicho proceso. La interfaz de usuario puede consistir desde una aplicación independiente hasta un terminal o incluso una pagina web. La misión de esta capa es únicamente contener la interfaz gráfica para interactuar con el usuario. Si se tienen distintos tipos de clientes (encargados de sección, cajeros...) con necesidades distintas y plataformas distintas, a la hora de implementarlos la cantidad de código a desarrollar será pequeña, ya que sólo habrá que escribir la interfaz de usuario. Si se utiliza un editor de interfaces gráficas la tarea se hace casi trivial. &DSD/yJLFDR$JHQWH La nueva capa que introduce el modelo es la capa intermedia, que será la encargada de manejar la lógica de la aplicación. Se denomina capa Agente o capa de Lógica de Negociado. Esta capa se verá como una especie de interfaz que proporcionará una serie de primitivas y datos a los que será posible acceder. De esta forma, se dispondrá de un conjunto de servicios que podrán ser usados por la capa cliente. El cliente deberá poder ser programado sin necesidad de conocer la implementación interna de la lógica de negociado. El objetivo es que las modificaciones realizadas a la capa lógica mantengan la interfaz (la apariencia externa) intacta, y no desemboquen en la modificación de ninguna de las otras dos capas. La principal función del agente es la de traducir y adaptar las peticiones del cliente (llamadas a las primitivas que proporciona la capa) a la semántica interna del servidor. En el Agente está centralizado además el acceso de los clientes al servidor, lo que aumenta la seguridad y la eficiencia. De este modo es posible realizar una mejor gestión de la carga del servidor. Se pueden introducir, por ejemplo, varios servidores y balancear la carga entre ellos, con lo que se consigue que él número de clientes pueda aumentar considerablemente.
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ &DSD6HUYLGRU Esta capa consiste en un gestor de bases de datos (DBMS). Hay que notar que, al existir muchos gestores de bases de datos distintos, cada uno de ellos posee rutinas de acceso diferentes. Esto haría que la capa lógica no fuera totalmente abstracta y dependiera fuertemente del gestor que se utilizara. Como se explicará posteriormente, este problema se puede solucionar gracias a SQL. Al estar estandarizado y existir puentes traductores de sentencias SQL a las propias del gestor, será posible trabajar de manera independiente al gestor de bases de datos utilizado. ,QWHUFRQH[LyQHQWUHFDSDV Otra de las características del modelo muy a tener en cuenta es la manera en la que se comunican las capas entre sí. La interfaz de usuario se comunicará con el agente, y éste a su vez lo hará con el gestor de bases de datos. Así pues, se tienen dos vías de comunicación que tendrán objetivos y necesidades distintas, por lo que se utilizarán elementos diferentes para cada una de ellas. (QODFH$JHQWH6HUYLGRU Los fabricantes de bases de datos suelen proporcionar rutinas de acceso al gestor de la base de datos, pero aunque proporcionan un acceso más rápido no es aconsejable utilizarlas si se quiere mantener la flexibilidad del sistema. Hay otras formas de comunicar al agente con la base de datos de manera que no se tengan que utilizar las rutinas propias de cada gestor. Esto se puede lograr utilizando ODBC o JDBC, gracias a los cuales todas las consultas contra la base de datos se realizarán en SQL. Será ODBC o JDBC, según el caso, el encargado de traducir las peticiones a la semántica propia del gestor que se esté utilizando. Esto permite cambiar el sistema gestor de bases de datos con relativa facilidad, ya que no habrá que modificar prácticamente nada en el código (solo la línea en que se especifica el gestor utilizado en el caso de JDBC) del Agente. (QODFH&OLHQWH$JHQWH Para comunicar el cliente con el agente existen varias posibilidades, entre las que se encuentran java-RMI, DCE, DCOM y CORBA. Si se quiere conseguir un producto flexible, portable y escalable, son estas dos ultimas la más adecuadas. En la actualidad DCOM es un producto que sólo esta disponible para plataformas Windows, y en cambio CORBA lo está para un gran numero de plataformas y lenguajes de programación. CORBA permite utilizar gran variedad de lenguajes de programación (existen implementaciones
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ de CORBA para C++, JAVA, Smalltalk, Ada 95, COBOL) con lo que el código del cliente y el del agente pueden estar escritos en lenguajes diferentes. Incluso se podrá cambiar el cliente o el agente sin necesidad de reescribir la otra capa.
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ Figura 4. Arquitectura Cliente-Servidor. Sobre este esquema se ha aplicado el modelo en tres capas estableciendo una capa para el Cliente, otra para el Agente (lógica de negociado) y una última para el Servidor de Bases de Datos. La figura siguiente representaría el nuevo esquema de la aplicación: Figura 5. Modelo en tres capas aplicado a la aplicación. &DSD&OLHQWH Como se observa en la figura anterior, se dispone de dos clientes que se comunican con el agente. Cada uno de ellos posee una interfaz de usuario
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ distinta, en la que se proporciona la funcionalidad necesaria para realizar las operaciones mencionadas anteriormente: introducir empleado, eliminar empleado y obtener datos de un empleado. Si la petición del usuario es “introducir empleado” o “eliminar empleado”, el cliente se limita a enviar la petición a la capa agente, que ejecutará las acciones necesarias para atenderla. Si la petición es “obtener empleado”, el cliente realiza la petición al agente, el cual ejecutará las acciones necesarias para devolverle los datos del empleado solicitados. Una vez el cliente tiene los datos, realiza un tratamiento sobre ellos; en este caso consistirá únicamente mostrarlos por pantalla. • &DSD$JHQWH El agente se encarga de atender las peticiones del cliente. Cuando el cliente llame a una operación, ésta se solicitará al agente, que la procesará de forma adecuada. Las operaciones pueden ser de consulta contra la base de datos o de modificación de la misma. • &DSD6HUYLGRU Esta capa contiene la base de datos de los empleados, y atiende a las peticiones de la capa agente proporcionando los datos requeridos si se trata de la operación “obtener empleado”, o bien modificando la base de datos si la operación es “introducir empleado” o “eliminar empleado”. Existen muchas configuraciones posibles a la hora de distribuir las capas del modelo en máquinas concretas, gracias a la versatilidad que proporciona el diseño utilizado. El sistema de tres capas propuesto está pensado para ejecutarse sobre varias máquinas localizadas en lugares diferentes. Cada uno de los clientes se podrá ejecutar en una máquina. Para ejecutar el cliente es necesario únicamente un navegador que se conectará con el servidor HTTP y ejecutará el applet JAVA que contiene la aplicación cliente. Este applet se comunicará con el agente utilizando CORBA. La comunicación se realizará entre el ORB del Cliente y el del Agente a través de Internet con el protocolo IIOP (Internet Inter ORB Protocol). El IIOP permite comunicar dos ORBs que se encuentren en redes distintas consiguiendo así un único ORB virtual. La comunicación entre el Cliente y el Agente también podría realizarse a través de una LAN evitando la utilización del IIOP, ya que el ORB del cliente y el Agente estarían en el mismo dominio. El Agente se encuentra en otra máquina y se comunica tanto con los clientes como con el Servidor de Bases de Datos. Para comunicarse con el
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ Servidor de Bases de Datos, el Agente utiliza JDBC, mediante el cual una aplicación JAVA puede realizar consultas en lenguaje SQL contra un servidor de Bases de Datos. JDBC puede utilizarse con cualquier servidor que reconozca el lenguaje SQL, por lo que resulta más flexible que cualquier producto concreto que se utilice para acceder a una base de datos concreta. Únicamente es necesario utilizar el driver JDBC correspondiente a la base de datos a la que se quiera acceder. En el caso de las bases de datos de Microsoft, es necesario utilizar un driver JDBC que adapta las peticiones a ODBC (driver de acceso a las bases de datos de Microsoft), el cual realiza la consulta concreta a la base de datos. En esta aplicación se ha utilizado el Servidor de Bases de Datos MSQL, presente en otra máquina diferente que recibe las consultas SQL del Agente y le proporciona los resultados de las mismas. Es importante tener en cuenta que no es esta la única configuración posible a la hora de implementar la aplicación, existiendo una gran cantidad de variantes. Se podría, por ejemplo, tener múltiples clientes repartidos por todas las máquinas, así como varios Agentes para repartir la carga de clientes. Incluso el Servidor de Bases de Datos puede encontrarse en cualquier otra máquina, mientras se indique su dirección IP en el código de implementación del Agente (la modificación es trivial, ya que sólo es necesario modificar una línea de código). Es posible, además, que tanto los clientes como el Agente estén implementados en cualquier lenguaje que soporte CORBA. El cliente únicamente debe respetar la interfaz que le proporciona el servidor. Si cambia la implementación del servidor, lo único que habrá que modificar será el acceso a la base de datos (JDBC es sólo para JAVA). 0RGHODGRGHODDSOLFDFLyQ 0RGHORGHFODVHV Para facilitar la comprensión del diagrama de clases no se han representado todas las clases utilizadas. El conjunto de las clases no representadas son las que implementan algunas de las operaciones internas de CORBA. El modelo de clases de la aplicación se corresponde con el siguiente diagrama.
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ 'HVFULSFLyQGHOPRGHORGHFODVHV Para la comprensión del modelo de clases es necesario tener presente que JAVA no permite herencia múltiple. Para emularla se utilizan LQWHUIDFHV que se declaran de manera abstracta y contienen la signatura de un conjunto de operaciones que han de ser definidas por otra u otras clases. • &ODVH(PSOHDGRV6HUYLGRU,PSO Esta es la clase que implementa la interfaz de (PSOHDGRV En ella reside la capa Agente, y será la encargada de proporcionar la interfaz que utilizará el cliente para realizar sus peticiones. Esta clase hereda de (PSOHDGRV6HUYLGRU,PSO%DVH que se encarga de implementar funciones
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ internas de CORBA, que se usan para gestionar la comunicación a través del ORB (al igual que todas las clases que terminen en ,PSO%DVH , que son generadas automáticamente por el compilador de IDL). Esta clase implementa las funciones: - SXEOLFV\QFKURQL]HGYRLG REWHQHU(PSOHDGR 6WULQJ U3ULPHU$SHOOLGR&OLHQWH$EVWUDFWRPLBFOLHQWH - SXEOLFV\QFKURQL]HGYRLG LQWURGXFLU(PSOHDGR 6WULQJU3ULPHU$SHOOLGR6WULQJU1RPEUH6WULQJ U6XHOGR - SXEOLFV\QFKURQL]HGYRLG HOLPLQDU(PSOHDGR 6WULQJ U3ULPHU$SHOOLGR Cuando finalice su ejecución, la operación REWHQHU(PSOHDGR llamará al método FDOOEDFN del objeto mi_cliente que se le pasa como parámetro pasándole los resultados para que ésta los procese (esto se explicará mas detalladamente en el punto 4.4). • &ODVH(PSOHDGRV6HUYLGRU Esta clase posee un objeto incrustado de tipo (PSOHDGRV6HUYLGRU,PSO que implementa la agregación con la clase (PSOHDGRV6HUYLGRU,PSO El objeto incrustado (PSOHDGRV6HUYLGRU,PSO será dado de alta en el ORB una vez inicializado este, y servirá para implementar la agregación que se establece de manera virtual, a través del ORB, entre (PSOHDGRV6HUYLGRU y (PSOHDGRV/HW (que corresponde al cliente) • &ODVHV&OLHQWH,PSO\&OLHQWH,PSO Estas dos clases son las encargadas de implementar los interfaces &OLHQWH\&OLHQWH que heredarán de la interfaz &OLHQWH$EVWUDFWR En ellas se encuentra únicamente la implementación de la operación - SXEOLFYRLG FDOOEDFN 6WULQJF1RPEUH 6WULQJF6XHOGR cuya signatura es igual para ambas clases, siendo su implementación distinta. Esta operación se encarga de procesar la información recibida del Agente, lo que se realiza de manera diferente en cada cliente. Las Clases Cliente1Impl y Cliente2Impl heredan de Cliente1ImplBase y Cliente2ImplBase. • &ODVHV(PSOHDGRV/HW\(PSOHDGRV/HW
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ Su función es implementar la capa cliente. Se dispondrá de dos clientes diferentes con interfaces de usuario distintas. Es necesario que ambas clases hereden de la clase Applet, debido a que en JAVA todos los applets deben hacerlo para redefinir los métodos LQLW UXQ y SDLQW . (PSOHDGRV/HW y (PSOHDGRV/HW se encargan de inicializar el ORB y de obtener la referencia al objeto de tipo (PSOHDGR6HUYLGRU,PSO , que utilizarán como objeto incrustado virtual para poder llamar a través de éste a las operaciones que implementa el servidor ( REWHQHU(PSOHDGRLQWURGXFLU(PSOHDGR\HOLPLQDU(PSOHDGR ). Gracias a la utilización de CORBA, el objeto (PSOHDGRV6HUYLGRU,PSO se podrá usar como si se hubiera declarado de la forma habitual, reduciéndose la llamada a los procedimientos implementados por el servidor a: - objetoServidorImplRemoto.obtenerEmpleado(...) 8WLOL]DFLyQGHOSDWUyQGHGLVHxR&DOOEDFN'LVWULEXtGRHQOD DSOLFDFLyQ El objetivo de la utilización del patrón callback en esta aplicación es hacer que el cliente pueda seguir trabajando de manera normal mientras el servidor está procesando una petición de REWHQHU(PSOHDGR Como se puede observar en la siguiente traza de ejecución correspondiente a la aplicación original, el cliente quedaba bloqueado tras ejecutar la petición, esperando que el servidor respondiera con el resultado. Esto hace imposible introducir nuevos empleados o eliminarlos mientras se espera el resultado. Figura 5. Traza de ejecución sin aplicar Callback.
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ Una vez introducido el patrón se consigue que, mientras se ejecute en el proceso servidor una petición de REWHQHU(PSOHDGR el cliente pueda seguir realizando peticiones. La nueva traza de ejecución sería la siguiente: Figura 6. Traza de ejecución aplicando Callback. En la figura se puede observar que, aunque el Agente admite múltiples peticiones del Cliente mientras se ejecuta en el Agente la operación REWHQHU(PSOHDGR , las peticiones se procesan de manera secuencial en el mismo orden en que produjeron. Esto es debido a que las operaciones de acceso a la base de datos ( LQWURGXFLU(PSOHDGR HOLPLQDU(PSOHDGR y REWHQHU(PSOHDGR ) están declaradas como V\QFKURQL]HG , lo que hace que no se puedan ejecutar de manera concurrente para mantener la consistencia de la base de datos. Nótese que, a pesar de que no puedan realizarse múltiples accesos a la base de datos al mismo tiempo, el cliente sí puede realizar tantas peticiones como desee, ya que estas se encolarán a la espera de que finalicen las operaciones anteriores. Para poder aplicar este patrón es necesario modificar el archivo IDL que contiene la especificación de la aplicación.: • El IDL original de la aplicación era:
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ Module EmpleadosAp { interface (PSOHDGRV { void REWHQHU(PSOHDGR ( LQ string rPrimerApellido, RXW string rNombre, o XW string rSueldo); void LQWURGXFLU(PSOHDGR ( LQ string rPrimerApellido, LQ string rNombre, LQ string rSueldo); void HOLPLQDU(PSOHDGR ( LQ string rPrimerApellido); }; }; Una vez aplicamos el patrón callback con la mejora para desacoplar cliente y servidor (agente en el caso de tres capas) pasaría a ser: Module EmpleadosAp{ Interface ClienteAbstracto; Interface (PSOHDGRV { RQHZD\ void REWHQHU(PSOHDGR ( LQ string rPrimerApellido, LQ ClienteAbstracto PLBFOLHQWH ); void LQWURGXFLU(PSOHDGR ( LQ string rPrimerApellido, LQ string rNombre, LQ string rSueldo); void HOLPLQDU(PSOHDGR ( LQ string rPrimerApellido); }; interface &OLHQWH$EVWUDFWR { RQHZD\ void FDOOEDFN ( LQ string cNombre, LQ string cSueldo); }; interface &OLHQWH :ClienteAbstracto{}; interface &OLHQWH :ClienteAbstracto{}; }; El procedimiento para transformar el antiguo IDL en el nuevo es el explicado en la sección 3.2.5. En este caso concreto, la única operación que requiere el uso del método callback es REWHQHU(PSOHDGR , ya que solicita datos al servidor para que éste se los devuelva como parámetros de salida. En la aplicación original sólo se disponía de un cliente. Ahora se han introducido dos clientes que poseen interfaces gráficas diferentes y procesan la
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ información recibida de manera distinta (implementaciones diferentes de la operación callback en cada uno de ellos). Como ya se ha explicado, el principal problema del patrón callback es que provoca un acoplamiento entre el cliente y el servidor, ya que en la operación REWHQHU(PSOHDGR se pasa como parámetro un objeto de tipo cliente para que el servidor pueda llamar a la operación callback de dicho cliente. Debido a que se tienen dos clientes distintos, se debería implementar una operación obtenerEmpleado sobrecargada para cada uno de ellos. Por cada cliente diferente se debería realizar una nueva sobrecarga de la operación obtener Empleado. Existe también la posibilidad de recibir un objeto del tipo genérico Object (del que heredan todas las clases), y chequear el tipo original del objeto. Una vez se conoce el tipo se ejecutaría una sección de código determinada (con sentencias LI , por ejemplo). Tanto la primera como la segunda solución provocarían que el cliente y el servidor estuvieran fuertemente acoplados. Con el objetivo de evitar este acoplamiento y solucionar así el principal problema del patrón, se ha aplicado una variante del patrón comando. La solución consiste en que el método REWHQHU(PSOHDGR reciba como referencia al cliente un objeto de tipo &OLHQWH$EVWUDFWR . La clase &OLHQWH$EVWUDFWR es una clase de tipo abstracto en la que se define el prototipo de la operación callback. Todos los clientes concretos heredan de dicha clase, y cada uno de ellos implementa la operación callback de manera diferente, según las necesidades del cliente concreto. De este modo es posible llamar a la operación REWHQHU(PSOHDGR utilizando cualquier tipo de cliente, siempre que éste tenga implementada la operación callback. Así se pueden añadir todos los clientes concretos que se desee, con la única condición de que hereden de la clase &OLHQWH$EVWUDFWR e implementen la operación callback. Como se observa en la figura, las clases que implementan el callback son &OLHQWH,PSO y &OLHQWH,PSO . Estas clases implementan las interfaces &OLHQWH y &OLHQWH , que a su vez heredan de la interfaz abstracta &OLHQWH$EVWUDFWR .
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$
3DWURQ&DOOEDFN'LVWULEXLGRSDUDDSOLFDFLRQHV&25%$ %,%/,2*5$)Ë$ [1] Client/Server Programing with JAVA and CORBA. Second Edition Robert Orfali, Dan Harkey. Editorial Wiley 1998 [2] CORBA Design Pattern, Thomas J. Mowbray, Raphael C. Malveau, Wiley, 1998. [3] Erich Gamma et al. “Design Patterns”. Addison-Wesley. 1994 [4] La Biblia de JAVA. Editorial Anaya.