38
Patrones de diseño Índice 1 Charla 1: Introducción a los patrones de diseño. Algunos patrones básicos................ 3 1.1 Por qué patrones....................................................................................................... 3 1.2 Patrones J2EE.......................................................................................................... 4 1.3 Singleton (GoF)....................................................................................................... 6 1.4 Facade (GoF)........................................................................................................... 8 1.5 Factory (GoF).........................................................................................................10 2 Ejercicio de la charla 1: Introducción a los patrones de diseño................................. 15 2.1 Refactorización basada en patrones....................................................................... 15 3 Charla 2: Patrones para las capas de presentación y negocio..................................... 16 3.1 Arquitecturas para la capa de presentación en aplicaciones web.......................... 16 3.2 Modelo-Vista-Controlador (MVC)........................................................................ 18 3.3 Algunos patrones para la capa de negocio............................................................. 24 4 Ejercicio de la charla 2: Patrones para aplicaciones web........................................... 26 4.1 La aplicación de bookmarks.................................................................................. 26 4.2 Implementación de un caso de uso con MVC....................................................... 27 4.3 Caso de uso "crear nuevo bookmark" (*).............................................................. 27 5 Charla 3: Patrones para aplicaciones enterprise......................................................... 28 5.1 Patrones para aplicaciones distribuidas vs. aplicaciones "locales"........................ 28 5.2 Fuentes bibliográficas para patrones enterprise..................................................... 28 5.3 Minimizando las llamadas remotas: Session Facade............................................. 29 5.4 Transfiriendo datos a los clientes: Transfer Object............................................... 31 5.5 Localizando servicios: Service Locator................................................................. 32 5.6 Haciendo transparentes los EJBs de negocio:Business Delegate.......................... 34 6 Ejercicio de la charla 3: Patrones para aplicaciones enterprise.................................. 35 6.1 Estructura de la aplicación..................................................................................... 36 6.2 Patrón fachada........................................................................................................ 36 Copyright © 2007-2008 Depto. CCIA All rights reserved.

Patrones de diseñoCatálogo de patrones de Core J2EE Patterns En los patrones que vamos a ver en el módulo mezclaremos por igual patrones J2EE con patrones genéricos. El resultado

  • Upload
    others

  • View
    9

  • Download
    0

Embed Size (px)

Citation preview

  • Patrones de diseño

    Índice

    1 Charla 1: Introducción a los patrones de diseño. Algunos patrones básicos................3

    1.1 Por qué patrones.......................................................................................................3

    1.2 Patrones J2EE.......................................................................................................... 4

    1.3 Singleton (GoF)....................................................................................................... 6

    1.4 Facade (GoF)........................................................................................................... 8

    1.5 Factory (GoF).........................................................................................................10

    2 Ejercicio de la charla 1: Introducción a los patrones de diseño................................. 15

    2.1 Refactorización basada en patrones....................................................................... 15

    3 Charla 2: Patrones para las capas de presentación y negocio.....................................16

    3.1 Arquitecturas para la capa de presentación en aplicaciones web.......................... 16

    3.2 Modelo-Vista-Controlador (MVC)........................................................................18

    3.3 Algunos patrones para la capa de negocio.............................................................24

    4 Ejercicio de la charla 2: Patrones para aplicaciones web........................................... 26

    4.1 La aplicación de bookmarks.................................................................................. 26

    4.2 Implementación de un caso de uso con MVC....................................................... 27

    4.3 Caso de uso "crear nuevo bookmark" (*).............................................................. 27

    5 Charla 3: Patrones para aplicaciones enterprise......................................................... 28

    5.1 Patrones para aplicaciones distribuidas vs. aplicaciones "locales"........................28

    5.2 Fuentes bibliográficas para patrones enterprise.....................................................28

    5.3 Minimizando las llamadas remotas: Session Facade............................................. 29

    5.4 Transfiriendo datos a los clientes: Transfer Object............................................... 31

    5.5 Localizando servicios: Service Locator................................................................. 32

    5.6 Haciendo transparentes los EJBs de negocio:Business Delegate.......................... 34

    6 Ejercicio de la charla 3: Patrones para aplicaciones enterprise..................................35

    6.1 Estructura de la aplicación..................................................................................... 36

    6.2 Patrón fachada........................................................................................................36

    Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 6.3 Patrón Business Delegate (*)................................................................................. 37

    Patrones de diseño

    2Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 1. Charla 1: Introducción a los patrones de diseño. Algunos patronesbásicos

    Aunque cada aplicación J2EE tiene peculiaridades que la hacen única, en el proceso dedesarrollo de casi todas las aplicaciones es necesario solucionar una y otra vez los mismosproblemas: autentificación del cliente, persistencia de datos, separación entrepresentación, lógica y control,... En lugar de reinventar continuamente la rueda, es muchomás productivo aplicar estrategias que ya hayan funcionado con anterioridad. Esta idea esla que lleva a la definición de los patrones software.

    1.1. Por qué patrones

    En ingeniería del software, un patrón (pattern) es una solución ya probada y aplicable aun problema que se presenta una y otra vez en el desarrollo de distintas aplicaciones y endistintos contextos. Es importante destacar que un patrón no es en general una solución enforma de código directamente "listo para usar", sino más bien una descripción de cómoresolver el problema y de ante qué circunstancias es aplicable.

    Los patrones software fueron popularizados en el libro Design Patterns: Elements ofReusable Object-Oriented Software, que trata de patrones genéricos, aplicables a unaamplia gama de contextos y a cualquier lenguaje orientado a objetos. Este libropopularizó el "movimiento" de patrones y se ha convertido en un clásico, ampliamentereferenciado y que muchos han tomado como base para añadir patrones nuevos. Losautores de Design Patterns... son Erich Gamma, Richard Helm, Ralph Johnson y JohnVissides, aunque de manera jocosa y popular son más conocidos como el Gang of Four.De hecho, en muchas publicaciones serias los patrones que aparecen en Design Patternsse referencian con las siglas GoF.

    Ante todo este floreciente movimiento en torno a los patrones cabe preguntarse sirealmente aportan beneficios. Se suele argumentar que los patrones ofrecen tres ventajasfundamentales:

    • Están ya probados: son soluciones que han sido utilizadas con anterioridad demanera repetida y se ha comprobado que funcionan.

    • Son reutilizables: corresponden con problemas que no son específicos de un casoconcreto, sino que se presentan una y otra vez en distintas aplicaciones.

    • Son expresivos: cuando un equipo de desarrolladores tiene un vocabulario común depatrones, se puede comunicar de manera fluida y precisa las ideas fundamentalessobre el diseño de una aplicación.

    Por supuesto, los patrones no pueden ser la solución a todos los problemas de diseño ydesarrollo de aplicaciones J2EE. Como cualquier herramienta o metodología sonsusceptibles de malos usos, y de abusos (uso "compulsivo" simplemente "porque sonbuenos"). La experiencia y el sentido común dictarán cuándo son apropiados y cómo

    Patrones de diseño

    3Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • utilizarlos.

    1.2. Patrones J2EE

    Los patrones J2EE están orientados específicamente a los problemas comunes a todaslas aplicaciones J2EE. Algunos están basados en los patrones originales mientras queotros son más específicos del tipo de problemas que surgen específicamente en J2EE,bien sea por los tipos de aplicaciones que se suelen desarrollar con la plataforma o por lascaracterísticas (o deficiencias, incluso) de la tecnología. Los primeros fueron publicadosen el libro Core J2EE Patterns, convertido también en un clásico dentro del "mundillo"J2EE. En la actualidad son muchos los libros y los sitios web dedicados íntegramente apatrones para aplicaciones J2EE o con algún apartado sobre ellos.

    Una versión resumida del catálogo de Core J2EE Patterns está disponible en su sitio web.Siguiendo la idea de dividir la arquitectura de una aplicación en varias capas, los patronesse clasifican atendiendo a la capa a la que pertenecen. En la figura 5 aparece el esquemageneral en la que se muestra la situación de cada uno de los 21 patrones en el modelo decapas y las relaciones que existen entre ellos. Iremos viendo con detalle algunos de estospatrones y sus interrelaciones en las distintas charlas del módulo.

    Patrones de diseño

    4Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Catálogo de patrones de Core J2EE Patterns

    En los patrones que vamos a ver en el módulo mezclaremos por igual patrones J2EE conpatrones genéricos. El resultado es una lista de patrones bastante ad-hoc, en cuanto alorden de explicación que seguiremos y en cuanto a los patrones que trataremos frente alos que dejaremos de lado. Hay que tener en cuenta que el objetivo no es dar una listaextensiva de los mismos. Si a los 21 patrones J2EE se les suman los 23 fundamentales delGoF surge un número demasiado elevado para las horas disponibles. Por ello se ha optadopor describir solo algunos. El criterio de inclusión no ha sido su importancia per se, sinoel hecho de que sea un patrón de uso habitual en aplicaciones J2EE. Para una lista depatrones más "estándar" se puede consultar cualquiera de los recursos especificados en labibliografía.

    Patrones de diseño

    5Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Junto al nombre de cada patrón especificaremos si se trata de un patrón J2EE o procededel GoF.

    1.3. Singleton (GoF)

    1.3.1. Problema a resolver

    Hay muchos casos en los que solo necesitamos una instancia de una determinada clase.Ejemplos típicos son clases que representan las preferencias del usuario o laconfiguración del sistema, o clases que sirven de interfaz con dispositivos físicos.

    En estos casos hay que asegurarse de poder obtener una referencia a dicha instancia desdecualquier punto del código, y que solo haya una instancia creada, para evitar posiblesproblemas o inconsistencias. Una posible solución es definir variables globales (o sea,static), pero esto tiene dos problemas:

    • Por descuido, se podría instanciar una misma variable en dos sitios distintos, lo que"machacaría" el valor anterior.

    • El orden y momento de inicialización de las variables depende del compilador, lo cualpuede ser delicado si unas dependen de otras y están en lugares distintos.

    1.3.2. Discusión y beneficios

    El patrón singleton nos permite asegurar que de una clase habrá solo una instancia, yproporciona un punto de acceso a ella global a todo el código. El diagrama de clases esmuy sencillo, ya que se compone de una única clase:

    Patrón singleton

    El método getInstance() nos sirve para obtener la referencia a la única instancia de laclase. Además dicha instancia está almacenada dentro de la propia clase como unavariable de tipo static (esto último puede resultar curioso, pero no deja de ser un "trucoingenioso" perfectamente legal para el compilador). Por supuesto el singleton tendrá otrosmétodos, los servicios que proporcione la clase.

    La implementación de un singleton podría hacerse de varias formas, pero casi siempre seutiliza el mismo tipo de código. Vamos a resumir las ideas que nos llevarán a laimplementación final:

    • Si el constructor de una clase es público, podrá llamarse desde cualquier otra. Portanto, si queremos asegurar un control de la creación de instancias, no podemos tenerun constructor público, debemos hacerlo privado:

    Patrones de diseño

    6Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • public class MiSingleton {private MiSingleton() {

    //aqui va el codigo del constructor}

    }

    • Evidentemente, aunque el código anterior sea una definición legal que compilaráperfectamente, no parece tener mucho sentido. Si el constructor es privado, solo sepodrá llamar desde un objeto de la clase MiSingleton. Pero ¡no podemos instanciarobjetos de esa clase, porque el constructor es privado!. La solución al aparente dilemaconsiste en utilizar un método estático para llamar al constructor:

    public class MiSingleton {private MiSingleton() {

    //aqui va el codigo del constructor}public static MiSingleton getInstance() {

    return new MiSingleton();}

    }

    //código aparte...MiSingleton ms = MiSingleton.getInstance();

    • Con esto ya conseguimos controlar el acceso al constructor y poder llamarlo desdefuera de la clase. Lo único que nos falta es asegurarnos de que en todo momentoexiste una única instancia de MiSingleton. El "truco" consise en almacenar dichainstancia dentro de la propia clase MiSingleton (como una variable static) y enintroducir código en getInstance que chequee si dicha instancia está creada o no,para devolverla o en caso contrario devolver un nuevo MiSingleton.

    public class MiSingleton {//la unica instancia que existe de esta claseprivate static MiSingleton unico = null;

    private MiSingleton() {//aqui va el codigo del constructor

    }public static MiSingleton getInstance() {

    //instanciar el singleton si no existeif (unico == null) {

    unico = new MiSingleton();}//devolver el singletonreturn unico;

    }}//código aparte...MiSingleton ms = MiSingleton.getInstance();

    Como puede verse, este código es una especie de "idea feliz" que consigue de formaelegante el objetivo que nos proponíamos. Aunque quizá esto podría conseguirse de otras

    Patrones de diseño

    7Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • formas, esta es ampliamente utilizada y conocida, por lo que merece la pena usarla enlugar de intentar formas propias de hacerlo (después de todo, esta "reutilización de ideas"es consustancial a la idea misma de patrones software).

    Aviso:El código visto no asegura que solo exista una instancia si se permiten varios threads (piénseseque pasaría si los dos threads comprueban "a la vez" que no existe una instancia del objeto y lacrean ¡por dos veces!). Consultad la bibliografía adicional para ver formas de solucionar esteproblema (basadas en general en el uso de synchronized).

    1.3.3. Relación con otros patrones

    En aplicaciones J2EE, son múltiples los casos en los que solo se necesita una instanciade un objeto para toda la aplicación (aunque a este objeto lo puedan llamar varios threadssimultáneamente). Piénsese por ejemplo en un objeto encargado de calcular costes deenvío de pedidos. Los costes según métodos de envío, plazos de recepción, peso delpaquete, etc. son información global para toda la aplicación, de modo que se puedeimplementar como un singleton.

    Un uso típico de este patrón en aplicaciones enterprise es para implementar un encargadoglobal de localizar recursos JNDI como por ejemplo conexiones JDBC, EJBs, etc. Esto eslo que se conoce como Service Locator.

    1.4. Facade (GoF)

    1.4.1. Problema a resolver

    Supongamos que tenemos un sistema complejo, que agrupa multitud de clases, y pararealizar una tarea tenemos que llamar a varios métodos de estas clases en una secuenciaprecisa. Por ejemplo, supongamos un sistema domótico en el que tenemos el siguientediagrama de clases

    Patrones de diseño

    8Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Sistema domótico inicial

    Imaginémonos las operaciones que hay que realizar al entrar en casa: hay que desactivarla alarma, poner el aire acondicionado a nuestra temperatura preferida, y encender lasluces. Esto se podría hacer con un código similar al siguiente:

    ...//de alguna forma, ya hemos obtenido una referencia a la alarma,configuración, aire y luces//y tenemos también el nombre de usuario y el password...//desactivar la alarmaalarma.desactivar(password);//obtener preferencias de usuarioPreferencias prefs = configuracion.getPreferencias(usuario);//poner el aire acondicionado a la temperatura deseadaFloat temp = (Float) prefs.getPreferencia("temperatura");aire.setTemp(temp.floatValue());//poner las luces en "auto" si es la preferencia del usuarioString luces = (String) prefs.getPreferencia("luces");if (luces.equals("auto"))

    luces.setAuto(true);...

    Como se ve, una operación tan sencilla en apariencia implica manejar un número elevadode objetos y métodos. salirDeCasa() sería igual de tedioso: apagar las luces, el aire,activar la alarma.... Un cliente que quiera invocar una de estas operaciones no deberíanecesitar tanto código.

    1.4.2. Discusión y beneficios

    Parece inmediata la idea de crear una clase a la que trasladaremos todo este código y a lacual puedan acceder los clientes que lo necesiten. Esto es ni más ni menos que un facade.

    Patrones de diseño

    9Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Patrón facade

    Un Facade (fachada) consiste en implementar un interfaz simplificado para unsistema complejo. La idea es implementar una clase con un interfaz sencillo y queencapsule los detalles de la interacción entre todas las clases del sistema. Es importantenotar que se sigue permitiendo el acceso directo a las clases del sistema a los clientes quenecesiten "acceso a bajo nivel" pero se simplifica la interacción para los que no necesitenmás que operaciones comunes.

    En aplicaciones J2EE, las fachadas se suelen utilizar para proporcionar un "frontal deservicios" de la capa de negocio. De este modo, la interacción de los clientes (web, swing,etc...) con esta capa se simplifica considerablemente. Como veremos en charlasposteriores, en aplicaciones distribuidas las fachadas también mejoran la eficiencia delsistema, ya que las operaciones "de fachada para adentro" serán todas locales y la únicallamada remota será la del cliente a la fachada.

    1.5. Factory (GoF)

    1.5.1. Problema a resolver

    El patrón factory pretende proporcionar una buena manera de instanciar objetos cuando laclase a la que pertenece el objeto instanciado puede cambiar, bien por modificaciones enel diseño o bien porque en tiempo de compilación no se conoce la clase exacta.

    Por poner un ejemplo concreto, supongamos que tenemos un sistema de mensajeríainstantánea. Los mensajes se pueden enviar a través de varios canales (TCP/IP, SMS,buzón de mensajes,...) y hemos implementado una serie de clases que nos permiten hacerel envío por ellos: EnvioTCP, EnvioSMS, EnvioBuzon,... todas estas clases implementan lamisma interfaz ICanal, y el usuario elige el medio a través del GUI del programa. Elcódigo que envía el mensaje podría ser similar al siguiente:

    Patrones de diseño

    10Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Mensaje mensaje;ICanal canal;...mensaje = GUI.getMensaje();nombreCanal = GUI.getOpcionEnvio();if (nombreCanal.equals("TCP"))

    canal = new EnvioTCP();else if (nombreCanal.equals("SMS"))

    canal = new EnvioSMS();else if (nombreCanal.equals("buzon"))

    canal = new EnvioBuzon();canal.enviar(mensaje)

    El código anterior es tedioso de modificar si se cambian los posibles canales de envío oaparecen canales nuevos (bluetooth, ...).

    Nota:Un principio básico de un buen diseño es que el código debería estar abierto a la extensiónpero cerrado a la modificación. Es decir, que el diseño debería ser tal que nos permitieraextender la funcionalidad donde fuera necesario, pero al mismo tiempo consiguiera que estaextensión no suponga cambios en el código ya existente. Cualquier modificación de código enfuncionamiento podría suponer la introducción de bugs en el sistema.

    Es evidente que el código anterior no cumple esta condición, ya que es necesario insertarlíneas de código y recompilar la clase para extender la funcionalidad.

    1.5.2. Simple factory

    Recordemos de nuevo ese principio básico del diseño que dice que hay que separar lo quevaría de lo que permanece igual. En nuestro caso hemos visto que al tomar la precauciónde usar una interfaz común para todas las clases lo que puede cambiar es la instanciaciónde la clase concreta que necesitamos. Por tanto, vamos a encapsularla y separarla delresto.

    Si tuviéramos una clase auxiliar que nos proporcionara instancias concretas de la clase ointerfaz deseados (en nuestro caso ICanal) podríamos hacer algo como:

    Mensaje mensaje;ICanal canal;...mensaje = GUI.getMensaje();nombreCanal = GUI.getOpcionEnvio();canal = FactoriaCanales.crearCanal(nombreCanal);canal.enviar(mensaje)

    Que es un código mucho más limpio que la versión anterior. Ahora trasladamos losdetalles de la instanciación a FactoriaCanales, que se ha convertido en una especie defactoría o fábrica de objetos:

    Patrones de diseño

    11Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • public class FactoriaCanales {public static ICanal crearCanal(String nombre) {ICanal canal;

    if (nombre.equals("TCP"))canal = new CanalTCP();

    else if (nombre.equals("SMS"))canal = new CanalSMS();

    else if (nombre.equals("buzon"))canal = new CanalBuzon();

    return canal;}}

    A primera vista parece que simplemente hemos trasladado el problema a la claseFactoriaCanales. Es parcialmente cierto, en el sentido en que todavía es necesariomodificar esta clase si se modifican o crean canales nuevos, pero no será necesariomodificar ni recompilar ninguna de las clases que llamen al métodoFactoriaCanales.crearCanal (que podrían ser muchas). Hemos acotado los cambiosnecesarios a una clase únicamente.

    Usando la terminología de patrones, la clase anterior es una "factoría simple" (simplefactory). No es exactamente el patrón factory sino una versión simplificada de este.Podéis compararar el diagrama UML del simple factory con el del factory del apartadosiguiente para ver las diferencias.

    Simple factory

    En el diagrama anterior, Cliente es cualquier clase que requiera los "servicios" delSimple Factory para crear objetos.

    Aviso:En algunas fuentes de referencia se da como patrón factory esto que no es sino una versiónsimplificada. Esto no supone un problema siempre que se tenga clarpo de qué se está hablando yla diferencia entre ambas "versiones".

    Patrones de diseño

    12Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 1.5.3. Factory method

    Supongamos que el problema anterior se complica: ahora tenemos que distinguir entreusuarios lite, que no pagan una cuota y por tanto tienen algunas restricciones (númeromáximo de SMS, tiempo máximo de conexión, tamaño más limitado del buzón,..) yusuarios pro, que tienen menos restricciones en la mensajería. Necesitamos por tantocrear un canal lite y pro de cada tipo (SMS, TCP,...). Para organizar el código de maneraflexible podemos usar el patrón factory method, a veces llamado simplemente factory.

    Este patrón es ligeramente más complicado que la versión anterior. Tenemos una factoría"genérica" que es una clase abstracta y sirve para "fabricar" un producto, tambiéngenérico (un interfaz o bien una clase abstracta). Siguiendo con nuestro ejemplo,tendríamos una clase abstracta FactoriaCanales cuyo método crearCanal devolveríaun nuevo ICanal. Las factorías "concretas" (clases que heredan de la clase de la factoría"genérica") sirven para "fabricar" productos concretos. En nuestro caso tendríamos dosclases que heredarían de FactoriaCanales: FactoriaCanalesLite yFactoriaCanalesPro, cuyo método crearCanal(tipo) devolvería objetos CanalTCP,CanalSMS, de tipo lite y pro respectivamente. La siguiente figura muestra el diagrama declases para el ejemplo.

    Factory method para objetos ICanal

    Esta es una forma del patrón que, aunque más compleja que el simple factory es másflexible y permite extender el sistema de una manera más elegante. Por ejemplo, laaparición de un nuevo tipo de usuarios digamos silver, con privilegios intermedios,conllevaría la creación de nuevas clases, como CanalSMSSilver y CanalTCPSilver,cuyas instancias las crearía una factoría FactoriaCanalesSilver. La ventaja de esteenfoque es que no requiere modificar prácticamente nada del código ya existente. Lasclases que envían y reciben mensajes simplemente trabajan con objetos ICanal y lasclases que necesiten obtener nuevas instancias de canales simplemente necesitan unareferencia al FactoriaCanales del tipo adecuado. Cambiando una simple línea de código(o un fichero de configuración) podemos convertir a un usuario lite en pro sin más quecambiar su FactoriaCanalesLite por una FactoriaCanalesPro.

    La siguiente figura muestra el diagrama de clases genérico del patrón.

    Patrones de diseño

    13Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Factory method: diagrama genérico

    Nótese que no siempre es necesario que un factory concreto cree más de un productodistinto. En nuestro ejemplo, cada subclase de FactoriaCanales creaba distintos tipos decanal, pero no siempre es así. En ese caso el método que actúa de factoría de objetos notendrá parámetros.

    Patrones de diseño

    14Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 2. Ejercicio de la charla 1: Introducción a los patrones de diseño

    2.1. Refactorización basada en patrones

    En esta sesión vamos a refactorizar el código de una aplicación basándonos en lospatrones de diseño vistos en la charla.

    La aplicación consiste en un lector de feeds RSS en el que podemos suscribirnos a unaserie de feeds y leer su contenido.El código de la aplicación se incluye en las plantillas dela sesión. Para simplificar el código del ejercicio, la aplicación carece de interfaz gráfico.

    Nuestro objetivo es refactorizar la parte de la aplicación que lee y guarda laconfiguración de cada uno de los feeds, teniendo en cuenta que:

    • La clase RSSReader es la clase principal, encargada de bajarse los feeds de Internet ymostrarlos adecuadamente formateados.

    • La configuración de un feed se representa con la clase FeedConfig. Por el momento,la propia clase RSSReader es la que lee/almacena las configuraciones.

    • En el prototipo inicial, la configuración de cada feed se guarda en un fichero.properties distinto, pero es de esperar que en la versión definitiva elalmacenamiento de la configuración cambie a un formato más complejo, como unsolo archivo XML.

    • Para simplificar el ejercicio, se implementa la parte que lee las configuraciones, perono la que las guarda.

    Se pide:

    • Revisar el diseño de la aplicación introduciendo los patrones que se considerenadecuados. No hay por qué aplicar todos los vistos en la charla.

    • Implementar dichos cambios en el código de la aplicación. Se recomienda hacer laimplementación de manera iterativa. Es decir, introducir los patrones de uno en uno,asegurándose de que todo funciona tras el cambio. NOTA: no es necesarioimplementar la configuración en XML, solo dejar el código preparado para que sepueda cambiar a XML de manera sencilla.

    Patrones de diseño

    15Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 3. Charla 2: Patrones para las capas de presentación y negocio

    En esta charla trataremos patrones para aplicaciones web basadas en servlets y JSP. En laprimera charla ya vimos algunos ampliamente usados en este tipo de aplicaciones: DAOs,Transfer Objects, façades, etc. Estos patrones se encuadran dentro de las capas de accesoa datos (DAO y TO) y negocio (TO y façade). Aquí veremos el primer patrón propio de lacapa de presentación: el Modelo-Vista-Controlador (MVC). Antes de presentarlo haremosun breve repaso a las distintas alternativas de diseño para la capa de presentación en unaaplicación web.

    3.1. Arquitecturas para la capa de presentación en aplicaciones web

    Teniendo en cuenta que servlets y JSP son equivalentes desde el punto de vista funcionaly que es mucho menos tedioso desarrollar un interfaz web en JSP que en servlets, lamayoría de aplicaciones web suelen usar JSPs para la capa de presentación o unacombinación de JSPs y servlets. Veamos cuáles son las opciones a la hora de diseñar laarquitectura de la capa de presentación.

    3.1.1. Aplicaciones JSP-céntricas

    En estas aplicaciones cada página JSP contiene todo el procesamiento asociado a un casode uso (por ejemplo hacer login en la aplicación) o de parte de un caso de uso (porejemplo, una de las páginas del proceso de registro de nuevo usuario). Lo más inmediatoa la hora de programar este tipo de aplicación es lo que podríamos llamar la "ausencia dearquitectura": poner todo el código de presentación, lógica de negocio y acceso a datosdentro de los JSPs. En aplicaciones pequeñas resulta una manera sencilla de "estructurar"el sistema, pero por razones evidentes en aplicaciones medianas o grandes esto seconvierte en una pesadilla de desarrollo y mantenimiento .

    Las especificaciones iniciales de JSP hablaban de solucionar los problemas anteriores conlo que Sun llamó el "modelo 1" de arquitectura para aplicaciones web. La idea básica esque el código de negocio y acceso a datos se "saca fuera" de los JSPs de modo que éstosse encargan únicamente de la presentación. La propuesta original habla de usar JavaBeanscomo encargados de "disparar" la lógica de negocio y el acceso a datos porque su uso ysintaxis son sencillos y son el modelo de componentes "estándar" en Java. Combinandoesto con el uso de taglibs propias o estándar (tipo JSTL) se puede eliminar el código Javadel JSP de modo que incluso diseñadores web no programadores podrían en teoríaocuparse en su totalidad de los JSP.

    Patrones de diseño

    16Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Arquitectura 'modelo 1'

    Nota:El modelo 1 se conoce en el catálogo de Core J2EE patterns como "View helper"

    3.1.2. Combinación de servlets y JSP

    Con la arquitectura anterior, el JSP no se dedica únicamente a presentar los resultados,sino que tiene más responsabilidades. Una alternativa es que para cada caso de uso hayaun servlet distinto que se encargue de tomar los parámetros de la petición, llamar a lalógica de negocio y colocar los resultados en algún ámbito que el JSP pueda consultar(porejemplo en la petición o en la sesión). El JSP se puede limitar a mostrar los resultadosobtenidos.

    Patrones de diseño

    17Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Combinación de servlets y JSP

    Aunque parezca que el flujo de ejecución se complica, en realidad se realizan las mismastareas, solo que en un orden ligeramente diferente y lo más importante: separandoresponsabilidades.

    1. Un servlet recibe la petición HTTP del cliente y analiza los parámetros2. El servlet activado dispara la lógica de negocio llamando al/los JavaBean/s

    correspondiente/s3. Los JavaBeans se encargan de ejecutar la lógica de negocio y el acceso a datos4. El servlet coloca los JavaBeans en algún ámbito al que un JSP pueda acceder.

    Típicamente se usaría el objeto request. Después llama al JSP apropiado.5. El JSP llamado, accede al JavaBean y muestra la información que contieneEste modelo presenta la ventaja con respecto al anterior de que el código del JSP sesimplifica todavía más. Estamos solo a un paso de la arquitectura más usada en laactualidad para aplicaciones web: Modelo-Vista-Controlador (MVC), que veremos acontinuación.

    3.2. Modelo-Vista-Controlador (MVC)

    Esta arquitectura se parece mucho a la combinación de servlets y JSPs que hemos vistoantes, con la única diferencia de que solo hay un servlet, que es el que recibe todas laspeticiones. ¿Cómo sabe entonces el servlet qué lógica de negocio hay que disparar y qué

    Patrones de diseño

    18Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • JSP es el apropiado para mostrar los resultados?. Esto se puede hacer por ejemplopasándole en la petición HTTP algún parámetro adicional que lo indique, como:

    http://.../aplicacionMVC/miUnicoServlet?accion=login&user=javaee&password=javaee

    En este ejemplo el parámetro accion es el que le indica al servlet qué es lo que hay quehacer. Los demás parámetros se necesitan para poder ejecutar la operación, aquí hacerlogin en el sistema. Luego veremos que hay otras alternativas (más usadas) a la hora dedecirle al servlet qué operación hay que ejecutar.

    3.2.1. Los componentes de la arquitectura: el modelo, la vista y el controlador

    Veamos de nuevo la arquitectura, pero ahora usando la terminología habitual de MVC:

    • El controlador (en nuestro caso el servlet) es el encargado de:

    1. Averiguar cuál es la operación a ejecutar2. Tomar los parámetros de entrada y disparar la lógica de negocio apropiada pasándole

    dichos parámetros.3. Colocar los resultados de la operación en algún ámbito accesible a un JSP

    (normalmente la petición)4. Redirigir al navegador al JSP apropiado• El modelo es la lógica de negocio y el código de acceso a datos. Aunque hasta ahora

    hemos hablado de JavaBeans, esto era una sugerencia de Sun para simplificar elinterfaz con el JSP. El modelo puede ser en realidad cualquier cosa: EJBs(componentes de negocio distribuidos), clases Java convencionales, JavaBeans, etc.

    • Las acciones son las operaciones a ejecutar para cada caso de uso de la aplicación.Podemos imaginarnos que cada acción encapsula de alguna forma todo elprocesamiento asociado a un caso de uso (o a parte de un caso de uso, dependiendo decómo modelemos el sistema). Las acciones se suelen considerar como parte delmodelo, aunque en realidad están en la frontera entre éste y el controlador.

    • La vista es el elemento encargado de mostrar los resultados obtenidos en el modelo.En nuestro caso, son los JSPs

    Nótese que cada petición HTTP implica una acción distinta y una vista distinta, mientrasque solo hay un controlador y un modelo, aunque cada petición requerirá partes distintasdel mismo: por ejemplo para buscar productos en el catálogo hará falta ejecutar distintalógica y acceder a distintos JavaBeans que para registrarse en la web.

    El diagrama de una posible arquitectura MVC (luego veremos que hay variantes) semuestra en la siguiente figura. Nótese que es muy parecido al de la combinación deservlets y JSPs que veíamos antes, con la única diferencia de la terminología y que solohay un servlet.

    Patrones de diseño

    19Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Modelo-Vista-Controlador

    Nota:El patrón de diseño MVC no es ni mucho menos exclusivo de aplicaciones web. Ni siquiera esoriginal del GoF. Fue descrito por primera vez en 1979, con el nacimiento del lenguaje Smalltalken Xerox, y hoy es ampliamente usado en multitud de frameworks, librerías y entornos GUI (sinir más lejos la librería Swing de Java). La web es solo uno de los contextos en los que se haaplicado hasta ahora la idea de MVC, y es importante tener en cuenta que el patrón tal y como seaplica en la web es una adaptación del patrón original al funcionamiento de HTTP.

    3.2.2. Una implementación de MVC

    Al ser éste un patrón complejo, tener una implementación concreta ayuda a comprender elfuncionamiento. Describiremos a continuación una implementación sencilla perototalmente funcional de MVC.

    Aviso:En una aplicación real, no es recomendable la estrategia de "reinventar la rueda". En JavaEE haydisponibles multitud de frameworks MVC de probada calidad, de los cuales el estándar de factoes Struts. Con un framework nos aseguramos de poder usar código e ideas ya probadas, nos serámás fácil encontrar desarrolladores ya preparados para trabajar y podremos aprovechar lasmuchas herramientas existentes para facilitar el desarrollo (en forma de plugins para Eclipse yotros IDES).

    Patrones de diseño

    20Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 3.2.2.1. El controlador

    En nuestro caso el controlador se implementa mediante un servlet. Esto es bastante típicode la mayoría de frameworks MVC.

    Configuración del web.xml

    El primer paso a realizar es configurar el descriptor de la aplicación (web.xml) para quelas peticiones con determinado patrón vayan todas a parar al controlador. Así, todas laspeticiones con un path común (por ejemplo /mvc/*) o con una extensión común (porejemplo, en Struts se suele usar *.do) irán a dicho servlet, que a partir de la URL decidecuál es la acción a disparar. En nuestro caso, el servlet se mapeará a todas las peticiones*.mvc

    Controladormvc.controlador.Controlador

    Controlador*.mvc

    Un refinamiento adicional sería restringir el acceso directo a todas las páginas del sitio,para que solo fueran accesibles a través del controlador. Esto se podría hacer por ejemplometiendo todas las páginas en un directorio protegido y especificando mediante unaetiqueta su condición de acceso restringido. No será necesarioespecificar ningún si no se desea acceso directo por parte de ningún usuario(en cualquier caso dicho acceso será posible a través del servlet). Una alternativa a larestricción de ciertas URLs sería colocar la web dentro de WEB-INF, que no esdirectamente accesible desde fuera del contenedor web. Hay que tener en cuenta que si seutiliza la restricción de acceso no será posible poner enlaces en las páginas de la formahabitual. Un simple salto entre páginas tendrá que ser ejecutado como una acción a travésdel servlet controlador. Esto según se mire puede ser tedioso (ya que complicamos unaoperación sencilla) o beneficioso (ya que abstraemos la URL de la página destino, lo quehace posible el cambio sin que por ejemplo queden afectados los bookmarks del usuario).

    Las acciones

    En el init() del servlet hay que crear la lista de acciones que el controlador puede ejecutar,y asignarle a cada una un nombre simbólico. En nuestro caso la lista de acciones está fijaen el código para simplificar el ejemplo, aunque lo más razonable sería mantenerla en unfichero aparte, por ejemplo en formato XML.

    Patrones de diseño

    21Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • public void init () throws ServletException {acciones = new HashMap();acciones.put("prueba", new AccionPrueba());acciones.put("login", new AccionLogin());...

    }

    Cada acción no es más que una instancia de una clase que se disparará (ejecutando ciertométodo) a petición del controlador. Procesamiento de las peticiones HTTP. En nuestrocaso, una acción concreta es una clase que debe heredar de la clase abstracta Accion, y eldisparo se realiza llamando al método ejecutar.

    Ciclo de procesamiento

    El ciclo de procesamiento de las peticiones es el siguiente:

    1. A partir de la URL se obtiene el nombre simbólico de la acción a ejecutar. En nuestrocaso es el nombre del "documento" solicitado, sin la extensión .mvc

    2. A partir del nombre simbólico de la acción, se obtiene una instancia de la acción aejecutar. En nuestro caso esto es sencillo, ya que se guarda una instancia de cadaacción en una tabla hash accesible por nombre.

    3. Se ejecuta la acción, llamando a un método. En nuestro caso todas las accionesimplementan el interface mvc.modelo.acciones.Accion, que obliga a definir unmétodo ejecutar. Para que la acción pueda cumplir su tarea habrá que pasarle lainformación contenida en el HttpServletRequest y probablemente también elHttpServletResponse. Frameworks MVC más sofisticados probablemente pasen estainformación como un objeto independiente del API de servlets, habiendo copiadoantes a él la información relevante, con el objeto de inpendendizar las acciones de lacapa HTTP.

    4. La acción coloca el resultado obtenido en algún sitio al que pueda acceder la vista(por ejemplo, como un atributo en el ámbito de la petición) y devuelve un valor que lesirve al controlador para determinar la siguiente vista a mostrar. En nuestro caso, laacción devuelve directamente el nombre del JSP a mostrar. En un caso más realistadevolvería un nombre simbólico que serviría para determinar el nombre real de lavista (por ejemplo, a través de un fichero de configuración).

    Nota:El encapsulamiento de los datos de la petición y la respuesta en un objeto independiente delprotocolo HTTP es un patrón de diseño que aparece en el catálogo de Core J2EE Patterns con elnombre de Context Object. En nuestro caso, la aplicación de dicho patrón serviría paraindependizar las acciones del protocolo HTTP, lo que permitiría su reutilización para clientes noHTTP, como por ejemplo clientes ricos Swing.

    Aquí solamente mostramos el esqueleto del procesamiento de peticiones, para ver cómose hace cada parte habrá que acudir al código fuente completo.

    Patrones de diseño

    22Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • public void doPost (HttpServletRequest request,HttpServletResponse response)

    throws ServletException, IOException {String nomAccion;Accion ac;String nomVista = null;

    try {//obtener de la URL el nombre de la acciónnomAccion = obtNomAccion(request);//a partir del nombre, obtener la clase asociada a la

    acciónac = getAccion(nomAccion);//ejecutar la accionnomVista = ac.ejecutar(getServletContext(), request,

    response);//mostrar la vista asociada a la accionif (nomVista!=null)

    mostrarVista(nomVista, request, response);}catch(MVCException e) {

    request.setAttribute("exception", e);mostrarVista(VISTA_ERROR, request, response);

    }}

    Nota:Esta implementación posiblemente deja "demasiadas responsabilidades" en manos delcontrolador, que tiene que hacer todo el trabajo de averiguar la acción a disparar, ejecutarla, pasarel resultado a la vista, etc. En el catálogo de Core J2EE Patterns se propone el patrón"Application Controller" que encapsularía el mapeo de acciones y su ejecución, lo que dacomo resultado una mayor modularidad del sistema y la posible reutilización del "ApplicationController" si este se hace independiente del protocolo de comunicación usando un "ContextObject" (ver nota anterior).

    3.2.2.2. El modelo

    Este es el punto donde suele terminar la "responsabilidad" del framework MVC yempieza el núcleo de nuestra aplicación.

    Como ya hemos comentado, en nuestro caso las acciones implementan el interfacemvc.modelo.acciones.Accion, que obliga a definir el método ejecutar.En general, loprimero que hará una acción es comprobar que los parámetros son del tipo esperado ycumplen una serie de normas de validación (por ejemplo, determinado formato para datostextuales, o estar en un rango para valores numéricos). La mayor parte de frameworksMVC proporcionan medios para que el usuario defina "validadores" de manera más omenos sencilla y configurable. Una vez la acción ha terminado su trabajo, debe colocarlos resultados en algún lugar accesible a la vista que debe mostrarlos. En nuestro caso, losalmacenaremos como atributos de la petición HTTP. Como el controlador se redirige alJSP que hace de vista con un forward, este tendrá acceso a dichos atributos.

    Patrones de diseño

    23Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Las acciones lo que harán será modificar y/o obtener el estado del sistema. Dicho estadoestará representado por un modelo orientado a objetos del dominio, en el cualrepresentaremos las entidades de nuestra aplicación. La "lógica de negocio" son losprocesos a realizar para cumplimentar alguna operación en el sistema. En una primeraaproximación es tentador introducir toda esta lógica dentro del cuerpo de las acciones.Así, por ejemplo, la acción RealizarPedido dentro de su método ejecutar podría chequearque el pedido es válido y el cliente no es moroso, aplicar el descuento apropiado al tipo decliente y plazo de pago e introducir el pedido en la base de datos mediante JDBC. Noobstante, hay que tener en cuenta que en algunos frameworks MVC las acciones están"acopladas" a la capa web (por ejemplo en Struts) y por tanto no son el lugar apropiadopara introducir dicha lógica, que debería ser lo más reutilizable posible para otros clientes(por ejemplo, "clientes ricos" Swing).

    3.2.2.3. La vista

    En nuestro caso una vista será simplemente una página JSP que se limitará a mostrar losdatos procesados por la acción. Idealmente, dichos datos estarán encapsulados en beansaccesibles a través del ámbito de la petición,con lo que el código Java a introducir dentrode la vista se reducirá al mínimo

    3.2.3. Variantes de MVC

    Siendo un patrón complejo, MVC admite multitud de variantes de funcionamiento. Noobstante, nos vamos a centrar aquí en diferenciar dos tipos de MVC: push y pull. Elesquema que hemos visto hasta el momento es de tipo push, ya que la vista recibe losresultados de la ejecución de la acción, ella no los dispara. En el catálogo de Core J2EEpatterns esto es lo que se conoce como el patrón "Service to worker". Un ejemplo real deimplementación de este patrón es el framework Struts.

    Una alternativa a este modelo sería el modelo pull, en el cual la vista es la responsable dedisparar la acción. En el catálogo de Core J2EE patterns esto es lo que se conoce como elpatrón "Dispatcher view". Un ejemplo real de framework que usa este enfoque esJavaServer Faces (JSF), que aunque se conoce básicamente como un modelo decomponentes GUI para la web también incluye un modelo MVC para el desarrollo de lasaplicaciones. En JSF, cuando se "dibuja" la página es cuando los beans asociados a lamisma disparan la lógica de negocio.

    3.3. Algunos patrones para la capa de negocio

    Para terminar esta discusión introduciremos brevemente algunos patrones para la capa denegocio. La función de muchos de estos patrones es proporcionar una capa de abstracciónsobre la implementación del sistema, de modo que por ejemplo no importe si laaplicación es local o distribuida, implementada con EJB3 o EJB2, ... Como en el cursotodavía no hemos visto en la práctica más que un modelo de arquitectura, el de las

    Patrones de diseño

    24Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • aplicaciones locales, haremos una primera aproximación a estos patrones "a vista depájaro" y volveremos sobre ellos en la última charla del módulo.

    En general no es interesante que los servlets/JSP o las acciones si usamos MVC llamendirectamente a la capa de acceso a datos (los DAOs), por varias razones:

    • Estamos introduciendo lógica de negocio en la capa de presentación, lo que nopermite reutilizar esta lógica si usamos otro tipo de cliente (por ejemplo un clienterico basado en Swing)

    • Los servlets/JSPs/acciones dependen del interfaz de las clases a las que llaman. Nopodemos cambiar el interfaz de los DAOs sin que este cambio repercuta en la capa depresentación.

    Para solucionar estos y otros problemas, en las aplicaciones JavaEE se pueden introducirdistintos patrones.

    3.3.1. Business Object

    Un business object no es más que un objeto del dominio de la aplicación. En el caso de labiblioteca del proyecto de integración tendríamos probablemente Usuario, Libro yOperacion. La diferencia entre un business object y un transfer object es que el primeroimplementará algo de lógica de negocio, mientras que el segundo es un mero "paquete dedatos" que viaja de un extremo a otro de las capas de la aplicación.

    Las aplicaciones sencillas pueden funcionar sin un modelo del dominio, es decir, sinbusiness objects. En este caso, los propios TO desempeñarían el papel (aunque de modorudimentario) de modelo de dominio. Este es precisamente el estadio en que se encuentraahora nuestra aplicación de biblioteca.

    3.3.2. Application Service

    La misión fundamental de este patrón es encapsular lógica de negocio, sobre todo la queimplica a más de un objeto. Por ejemplo, en el caso de la biblioteca, la operación deprestar un libro no se debe implementar en la clase Operacion, ya que no solo involucra aesta sino también a Usuario (hay que comprobar si un usuario es moroso antes de realizarel préstamo).

    El application service se suele apoyar en DAOs y business objects para realizar su labor.

    3.3.3. Session Façade

    La misión fundamental de este patrón es la de actuar como fachada de la capa de negocioen aplicaciones distribuidas. Por ello lo abordaremos en profundidad cuando en el cursohayamos trabajado con este tipo de aplicaciones.

    El session façade es cliente del Application Service o bien de los business objects si éste

    Patrones de diseño

    25Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • no existe.

    3.3.4. Business Delegate

    Este patrón constituye el "punto de entrada" a la capa de negocio desde la capa depresentación. La misión de este patrón es aislar a la capa de presentación de la de negocioen dos aspectos:

    • En aplicaciones distribuidas, aislar de los detalles de la comunicación remota.• En aplicaciones en las que la implementación de la capa de negocio pueda cambiar de

    un "paradigma" a otro, aislar del API de negocio. Por ejemplo, un cambio de EJB 2.0a EJB3.

    Como todavía no hemos visto en el curso aplicaciones distribuídas ni tecnologías para laimplementación de componentes de negocio, dejaremos la discusión de estos aspectospara más adelante.

    El business delegate es cliente del session façade.

    Como se ve, estos patrones se apoyan unos en otros, generando diversas capas que por unlado aportan flexibilidad y encapsulamiento a nuestra arquitectura pero por otro añadencomplejidad. La experiencia y el sentido común nos dirán en cada caso qué patrones sonnecesarios en nuestro proyecto y cuáles podemos obviar, si los beneficios que aportan nocompensan la complejidad de su implementación y uso.

    4. Ejercicio de la charla 2: Patrones para aplicaciones web

    Usando como contexto la aplicación incluida en las plantillas de la sesión, vamos aimplementar un par de acciones MVC para captar mejor todas sus implicaciones.

    4.1. La aplicación de bookmarks

    En las plantillas de la sesión se incluye una aplicación muy sencilla para gestionarbookmarks on line.

    La aplicación está dividida en dos proyectos: el proyecto java Bookmarks, con las capasde negocio y acceso a datos, y el proyecto web WebBookmarks, con la implementación deMVC "casera" vista en las transparencias.

    Para empezar a trabajar con la aplicación lo primero es crear la base de datos. En lacarpeta "db" se incluye un script de ant para ello.

    Para comprobar la aplicación, ejecutar el JSP test/testDAO.jsp. Debería aparecer unalista con los bookmarks que hay actualmente en la base de datos.

    Patrones de diseño

    26Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 4.2. Implementación de un caso de uso con MVC

    Implementa el caso de uso "listar bookmarks" usando Modelo-Vista-Controlador. Paraello, en el proyecto web tendrás que:

    • Definir una nueva clase jtech.mvc.acciones.AccionListar, que implemente elinterface IAccion. En dicha clase debes implementar la operación de listarbookmarks:1. Llamando al método listarBookmarks del DAO IBookmarkDAO. La instancia de

    este se obtiene a través de la FactoriaDAOs. Puedes mirar el código del JSPtest/testDAO.jsp.

    2. Colocando en el request el List obtenido del DAO.3. devolviendo lista como resultado de ejecutar la acción.

    • Añadir la clase AccionListar al Hashmap del servlet controlador.• Implementar la página lista.jsp para que, haciendo uso de JSTL, se muestre la lista

    de bookmarks. Puedes mirar el código del JSP test/testDAO.jsp. Fíjate que en elJSP no debería aparecer nada de código java, solo JSTL y expresiones en EL (${...}).

    4.3. Caso de uso "crear nuevo bookmark" (*)

    Implementa el caso de uso "crear nuevo bookmark". Necesitarás un HTML con unformulario para introducir los datos del nuevo bookmark y una acción que recoja esosdatos y cree el bookmark llamando al DAO.

    Patrones de diseño

    27Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 5. Charla 3: Patrones para aplicaciones enterprise

    Como sabe perfectamente Peter Parker, "un gran poder conlleva una granresponsabilidad". El desarrollador de aplicaciones enterprise con Java EE tiene a sudisposición un gran número de herramientas y tecnologías para diseñar e implementaraplicaciones a gran escala. Precisamente esta escala es la que hace que usaradecuadamente dichas tecnologías sea más crítico si cabe que en el caso de aplicacionesweb, que suelen tener un tamaño menor y una arquitectura más simple. Los patronesenterprise van a ayudarnos dándonos una guía de "buenas prácticas" específicas para estetipo de aplicaciones.

    5.1. Patrones para aplicaciones distribuidas vs. aplicaciones "locales"

    Además de la escala, dos son las características fundamentales de una aplicaciónenterprise frente a una aplicación web "convencional"

    • La posibilidad de distribuir la aplicación en varias máquinas físicas y/o lógicas• El uso de los servicios proporcionados por un servidor de aplicaciones, como JNDI o

    EJBs

    De las dos, la que tiene un impacto mayor a priori sobre el rendimiento es la primera:estar ejecutando llamadas remotas entre objetos a través de la red incurre en costes que, sibien tomados de modo individual son pequeños (del orden de milisegundos) si no segestionan eficientemente pueden dar lugar a enormes "cuellos de botella". Algunos de lospatrones que veremos van destinados precisamente a solucionar este problema: organizarla aplicación de un modo eficiente para que el coste extra de las llamadas remotas tenga elmenor impacto posible sobre el rendimiento. El caso prototípico es el del patrón sessionfaçade

    Por otro lado, la "herramienta" paradigmática para el desarrollo de aplicacionesdistribuidas en Java EE son los EJBs. Hasta la aparición de la versión 3 de laespecificación, los EJBs eran muy potentes pero también poco eficientes y de unacomplejidad considerable para el programador. Aparecieron diversos patrones nacidosúnicamente para ocultar y compartimentar la complejidad de los EJBs y para minimizar elimpacto en la eficiencia. Es decir, eran patrones que venían a "parchear" los defectos dela tecnología. La versión 3 de los EJBs alivia la situación, dando la misma potencia conun uso mucho más sencillo. Esto también hace que muchos de los patrones antiguos ya nosean necesarios o al menos no tan críticos como lo fueron en el pasado. La discusión quesigue supondrá que estamos usando la versión 5 de JavaEE o superior. Podemos consultarla bibliografía para información sobre cómo serían los patrones si en un proyecto nosviéramos obligados a usar EJB 2.x.

    5.2. Fuentes bibliográficas para patrones enterprise

    Patrones de diseño

    28Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Parte del interés de un patrón radica en su "reconocimiento" por parte de la comunidad.Un patrón no solo debe resolver un problema: además es una "pieza" que otrosdesarrolladores deberían reconocer al instante al verla aparecer en un diseño. Es obvioque el vocabulario común facilita la documentación y la comunicación entre el equipo detrabajo. Es por ello que en patrones se vuelve vital el conocimiento de las fuentesbibliográficas más "influyentes". Y es también por ello que no relegamos la bibliografíaal sitio habitual, que suele ser el final de los temas.

    Ya vimos en la primera charla que el trabajo más conocido en patrones de diseñogenéricos era el del Gang of Four (GoF). En el contexto de aplicaciones enterprise hansurgido en los últimos años varios trabajos influyentes. Algunos de ellos son aplicables acualquier plataforma tecnológica, mientras que otros son específicos para Java Enterprise:

    • Patterns of Enterprise Application Architecture, Martin Fowler, Addison Wesley:aplicable a cualquier aplicación enterprise, independientemente de la plataforma deimplementación. El libro incluye ejemplos en Java y C++. Los patrones puedenconsultarse online en el sitio de Martin Fowler, aunque en la web solo se pone unabreve explicación, mucho más corta que la discusión en profundidad del libro.

    • Core J2EE Patterns, Alur, Crupi & Malks: patrones específicos para Java EE. Enrealidad, son propios de la "época" pre-Java EE 5, por lo que no incluyen nada de laúltima revolución en la plataforma. Por ello, aunque interesante, el libro se haquedado anticuado. Procede de un tiempo en el que la tecnología tenía un montón deinconvenientes y problemas que era necesario evitar usando ciertos trucos y siguiendoformas muy específicas de hacer las cosas.

    • Sun dispone de un sitio web llamado "Java Blueprints". En tiempos fue la fuente dereferencia fundamental de "buenas prácticas". Hoy en día no se actualiza al mismoritmo que hace unos años, aunque se van incorporando poco a poco patrones quetienen en cuenta la versión 5 de Java EE.

    5.3. Minimizando las llamadas remotas: Session Facade

    5.3.1. Problema

    Ejemplo: una aplicación que permite enviar mensajes entre usuarios. La aplicación esdistribuida y la capa web está en una máquina distinta a la capa de negocio. La capa webestá implementada con Struts y la de negocio con EJBs de sesión y DAOs JDBC. Como alos EJBs se puede acceder desde cualquier objeto Java buscándolos con JNDI, la acciónde Struts podría acceder directamente a todos los EJBs necesarios para un caso de uso. Enla figura se muestra cómo funcionaría el caso "enviar mensaje", que requiere de lacolaboración de dos EJB, para el envío del mensaje (MensajeBO) y para el cobro delenvío al usuario (UsuarioBO).

    Patrones de diseño

    29Copyright © 2007-2008 Depto. CCIA All rights reserved.

    http://www.martinfowler.com

  • Acceso directo a los objetos del dominio

    Esta forma de trabajar es problemática por varias razones:

    • Desde el punto de vista lógico: ya hemos visto en módulos anteriores que una acciónde Struts, o cualquier otro tipo de cliente de la capa de negocio no debe implementarnada de lógica de negocio. En el ejemplo anterior incumplimos la norma, ya que laacción está "viendo" la estructura interna del caso de uso.

    • Desde el punto de vista de costes: un caso de uso implica normalmente a más de unbean de entidad. Si el cliente tiene que acceder de manera remota a cada uno de estosbeans de entidad, debe hacer múltiples llamadas a través de RMI con el alto coste queesto conlleva.

    • Desde el punto de vista de la integridad transaccional: los EJBs pueden gestionar deforma automática la transaccionalidad, pero cada operación con un bean distinto seejecutaría en una transacción separada. Podríamos usar JTA para agruparlo todo demanera manual, pero entonces se perdería parte del beneficio de los EJBs: el manejoautomático y declarativo de transacciones.

    Por tanto necesitamos algún mecanismo que nos permita: reducir la comunicación porla red, colocar la lógica de negocio de forma coherente y agrupar las operaciones enuna única transacción declarativa.

    5.3.2. Solución

    Utilizar el patrón Session Facade. En este, los EJBs de sesión forman el "frontal" de lacapa de negocio, ofreciendo un API de métodos al que pueden acceder los clientes.

    Uso de session façade

    El session façade es un EJB de sesión para poder aprovechar los beneficios que nos danlos EJBs: acceso remoto transparente, transaccionalidad y seguridad declarativas ygestión automática del ciclo de vida.

    Independientemente de la mejora de eficiencia, puede verse que este patrón es unaimplementación mediante un EJB de sesión del Facade del GoF, que se usa también en

    Patrones de diseño

    30Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • aplicaciones sin EJBs para centralizar la lógica de negocio.La única diferencia deimplementación es que en aplicaciones convencionales la fachada es un POJO local yaquí, como hemos visto, es un EJB de sesión remoto.

    Un problema práctico es cuántos Session Façades hay que definir en una aplicación. Lomás sencillo es definir uno solo, que contendría todo el API de la capa de negocio, peroeste enfoque lleva a clases con demasiado código no relacionado entre sí. La prácticacomún es agrupar los casos de uso relacionados (que actúan sobre las mismas entidades)en un Session Facade propio.

    5.3.3. Posibles problemas

    Como consecuencias negativas, un uso inadecuado del patrón puede llevar a:

    • Crear beans de sesión con mucho código y difíciles de gestionar si no se tiene unadisciplina clara para separar casos de uso.

    • Dar demasiadas competencias al Session Facade, colocándole la lógica interna deobjetos del dominio, que éstos deberían manejar por sí mismos.

    • Duplicación de código común a varios casos de uso. Cuando se detecte este códigodebe sacarse fuera del Session Facade y colocarse en POJOs en la capa de negocio,formando un patrón Application Service, es decir, una capa auxiliar que contienelógica de negocio.

    5.4. Transfiriendo datos a los clientes: Transfer Object

    5.4.1. Problema

    Ejemplo: una acción de Struts accede de forma remota a un EJB con los datos de unpedido. Cada llamada a un getter del EJB es en realidad una llamada remota, lo cual esclaramente ineficiente. No obstante necesitamos transferir de algún modo los datos delpedido desde negocio hacia presentación. Buscamos por tanto la manera menos costosade transferir información entre capas que residen en máquinas distintas.

    5.4.2. Solución

    Realizar la transferencia de información entre capas empaquetada en objetos del tipoDTO, Data Transfer Objects, que en su versión más sencilla son simplemente JavaBeans.Las operaciones serán mucho más eficientes con una única llamada que transfiera unpaquete de información en lugar de con múltiples llamadas con datos individuales. Porsupuesto, los DTOs también se usan en aplicaciones no distribuidas, pero en este caso suuso está más justificado por cuestiones de organización de código (1 parámetro en lugarde varios) que por la eficiencia.

    Aquí es donde podemos ver la justificación de por qué los DTOs deben ser serializables:si la aplicación pasa de ser local a distribuida, los DTOs van a viajar entre distintas JVMs

    Patrones de diseño

    31Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • . Aunque esta condición no sería estrictamente necesaria para una aplicación local, esmuy fácil de seguir desde el principio y nos protege ante posibles cambios en laarquitectura.

    5.4.3. Posibles problemas

    Para muchos desarrolladores, los DTOs son un "mal necesario". Son objetos sincomportamiento, solo con estado, lo que los hace más parecidos a un struct de C que averdaderos objetos. Irónicamente, algunos dicen que cuando se usan DTOs lo que se tienees un "modelo del dominio con anemia" (anemic domain model). No obstante, con losAPIs de hace unos años eran la única forma eficiente de transferir datos entre capas. Laaparición de JPA ha hecho posible usar entidades persistentes con estado ycomportamiento y mover dichos objetos a través de todas las capas de la aplicación:desde el almacén de datos a la presentación. Por eso el DTO es considerado en laactualidad por algunos como un patrón y por otros como un "antipatrón" o una formaincorrecta de hacer las cosas.

    5.5. Localizando servicios: Service Locator

    5.5.1. Problema

    Supongamos que una acción de Struts necesita acceder a un EJB remoto. En JavaEE 5 elcontenedor nos da acceso "automático" a los EJBs y otros recursos mediante la inyecciónde dependencias. Pero esta inyección de dependencias solo es aplicable a objetosgestionados por el contenedor, lo que no es el caso de una acción de Struts. Por tantonecesitamos usar el API JNDI para localizar el EJB. Tendremos que usar un códigosimilar al siguiente:

    Properties props = new Properties();props.setProperty(...)props.setProperty(...)...InitialContext ic = new InitialContext(props);UsuarioBORemote ubo;ubo = (UsuarioBORemote) ic.lookup("jtech.UsuarioBORemote");

    No solo esta acción, todas las clases no gestionadas por el contenedor que necesiten deEJBs o de otros recursos del servidor de aplicaciones necesitan de un código equivalente.No es excesivamente complicado, pero es tedioso y repetitivo. Además parte del códigoJNDI es dependiente del servidor, por lo que conviene aislarlo del resto del código parafacilitar la portabilidad. En concreto el Properties necesario para crear elInitialContext depende del servidor de aplicaciones y también el propio nombre JNDI(en el ejemplo se ha usado la convención de Glassfish, que es poner el nombre completode la clase, pero en otros servidores no es así) . Nuestro objetivo es proporcionar un"responsable centralizado" para localización de recursos JNDI.

    Patrones de diseño

    32Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 5.5.2. Solución

    Utilizar el patrón service locator para implementar y encapsular la búsqueda de recursos.El service locator esconde al cliente las posibles complejidades de la búsqueda,proporciona un API uniforme y puede mantener una cache para evitar llamadasinnecesarias a JNDI. Normalmente no hará falta más de un service locator para toda laaplicación, por lo que se puede utilizar para su implementación el patrón singleton delGoF.

    La siguiente figura muestra el diagrama de clases del patrón.

    Service Locator

    Como se ve, el Service Locator (que es un singleton) recibe solicitudes de los clientespara localizar recursos JNDI. Al inicializarse,el Service Locator crea un contexto inicialJNDI. Cada vez que recibe una solicitud de un recurso JNDI hace uso de dicho contexto.Mantiene además una Cache con los recursos ya solicitados para evitar peticiones JNDIinnecesarias.

    5.5.3. Consecuencias

    Las consecuencias positivas son:

    • Abstrae la complejidad: se encapsula el mecanismo de localización de servicios demodo que el cliente no necesita conocer los detalles.

    • Proporciona un interfaz uniforme de acceso a recursos: que pueden usar todos los

    Patrones de diseño

    33Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • clientes y que abstrae de las posibles características propias de la implementaciónJNDI empleada.

    • Mejora el funcionamiento de la aplicación: mediante la cache se evitan llamadasinnecesarias a JNDI

    Patrones relacionados

    • Singleton (GoF): normalmente en una aplicación bastará con tener un único ServiceLocator, por lo que este patrón se suele implementar como un singleton.

    • Data Access Object: un DAO normalmente utiliza un Service Locator para acceder afuentes de datos JDBC.

    • Business Delegate: en aplicaciones con componentes remotos utiliza un ServiceLocator para localizar servicios.

    5.6. Haciendo transparentes los EJBs de negocio:Business Delegate

    5.6.1. Problema

    Siguiendo con los ejemplos anteriores: si una acción de Struts necesita de un EJB,estamos haciendo su código dependiente de la implementación de la capa de negocio.Aunque el service locator abstrae los detalles de JNDI, sigue quedando claro que detráshay un EJB. Si queremos reducir al mínimo el acoplamiento tenemos que "ocultar" lanaturaleza de la capa de negocio.

    //La clase de la capa de presentaciónpublic class AccionLogin extends Action {public ActionForward execute(ActionMapping mapping, ActionForm

    form,HttpServletRequest req, HttpServletResponse resp){LoginForm lf = (LoginForm) form;ServiceLocator sl = sl.getInstance();//se conoce la implementación de la capa de negocioUserFacadeRemote uf =

    sl.getEJBResource("jtech.UserFacadeRemote");return uf.login(login, password);...

    }}

    5.6.2. Solución

    El business delegate: una fina "capa" entre presentación y negocio que oculta a la primerala tecnología usada para la implementación de la segunda. El BD es simplemente unPOJO. Aunque desde el punto de vista lógico pertenece a la capa de negocio (y como taldeben ocuparse de él los desarrolladores de esta capa), desde el punto de vista físico sedebe colocar en la capa de presentación para que las comunicaciones con los objetos deesta última sean locales. Los clientes que solicitan sus servicios no tienen por qué saber

    Patrones de diseño

    34Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • que estos son accedidos en realidad de forma remota.

    //La clase de la capa de presentaciónpublic class AccionLogin extends Action {public ActionForward execute(ActionMapping mapping, ActionForm

    form,HttpServletRequest req, HttpServletResponse resp){LoginForm lf = (LoginForm) form;//Aquí habría que poner un factory, mejorBUsuarios bdu = new BDUsuarios();//¿quién diría que detrás hay EJBs remotos?UsuarioTO u = bdu.login(lf.getLogin(), lf.getPassword());...

    }}

    //El business delegatepublic class BDUsuarios {public void UsuarioTO login(String login, String password) {ServiceLocator sl = sl.getInstance();//conoce la implementación de la capa de negocioUserFacadeRemote uf =

    sl.getEJBResource("jtech.UserFacadeRemote");return uf.login(login, password);}

    }

    5.6.3. Posibles problemas

    La transparencia en las llamadas remotas que ofrece el BD podría causar un mal uso delpatrón: que los desarrolladores de la capa de presentación olviden que los métodos denegocio son en realidad remotos y acaben haciendo un uso ineficiente y poco optimizadode las llamadas.

    Por otro lado, el BD es una capa más, que introduce un nivel de complejidad adicional.Dicho nivel de complejidad solo está justificado en caso de que sea realmente necesarioreducir al mínimo el acoplamiento entre presentación y negocio. Un ejemplo sería unaaplicación que comienza siendo web, con una capa de negocio basada en POJOs y luegopasa a usar EJBs. En ese caso el BD nos permite no tener que cambiar el código de lacapa de presentación.

    6. Ejercicio de la charla 3: Patrones para aplicaciones enterprise

    Tenemos una aplicación con una pequeña "red social". En dicha red los usuarios puedenenviarse mensajes unos a otros. Se trata de refactorizar el caso de uso de "enviarmensaje", introduciendo patrones que mejoren la eficiencia del sistema y la modularidaddel diseño.

    Patrones de diseño

    35Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 6.1. Estructura de la aplicación

    La aplicación está dividida en dos proyectos NetBeans: un proyecto web basado en Strutsy un proyecto ejb con la capa de negocio y de acceso a datos. Los dos proyectos están enlas plantillas de la sesión. Además se incluye un script SQL con la base de datos. Podéiscrear la BD con dicho script desde el programa "MySQL query browser": Se abre el .sqlcon la opción File > Open Script y se ejecuta con el botón "Execute" de la parte superiorderecha de la pantalla. Creará una BD llamada "amigos" con dos tablas.

    Comprobad que la aplicación funciona correctamente desplegando los dos proyectos enGlassFish. Primero desplegar el proyecto "amigos-negocio" y luego "amigos-web".Probar que se puede enviar un mensaje del usuario "maria" al usuario "pepe". Observadque como el envío de mensaje tiene un coste de 2 unidades, habrá usuarios que no puedanenviar el mensaje si no tienen crédito suficiente. La aplicación no dará error pero si veisla BD observaréis que el mensaje no se inserta en la tabla.

    La acción de EnviarMensajeAccion debe interactuar con dos EJB de la capa de negocio,los dos remotos:

    • GestorMensajesRemote: el encargado del envío del mensaje, es decir, de insertar elmensaje en la tabla "mensajes" con JPA.

    • GestorUsuariosRemote: el encargado del cobro del mensaje. Si el usuario tienecrédito suficiente se disminuye en dos unidades

    Hay que tener en cuenta que:

    • Como las acciones de Struts no son objetos gestionados por el contenedor, debemosusar JNDI para acceder a los EJBs

    • Si se envía el mensaje pero no hay crédito suficiente, se hace un rollback de latransacción, usando JTA

    6.2. Patrón fachada

    Introducir el patrón fachada en la aplicación. Dicha fachada será un nuevo EJB. La acciónEnviarMensaje únicamente comunicará con este EJB, que será el encargado de a su vez"hablar" con el GestorMensajes y con el GestorUsuarios

    1. En el proyecto "amigos-negocio" crear un nuevo EJB de sesión sin estado llamado"Fachada" (es decir, la clase de implementación se llamará FachadaBean y el interfazremoto FachadaRemote). No necesitamos interfaz local, ya que a la fachada solo seaccede desde "fuera". El interfaz remoto tendrá dos métodos:

    void enviarMensajeRemote(MensajeTO mto)void getUsuarioRemote(String login)

    Solo implementaremos el primero, el segundo puedes dejarlo vacío en laimplementación.

    Patrones de diseño

    36Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • 2. Traslada el código que creas necesario del "execute" de la acciónEnviarMensajeAccion al "enviarMensajeRemote" de la fachada. Ten en cuenta que laacción ahora solo debe "hablar" con la fachada. La fachada es la que "hablará" con elGestorMensajes y el GestorUsuarios. En la acción EnviarMensajeAccion sigue siendonecesario JNDI para localizar la fachada pero la fachada puede usar inyección dedependencias para comunicarse con los otros dos EJBs

    3. Quita el código JTA de la acción EnviarMensajeAccion. Ya no es necesario, porquelas transacciones las va a gestionar la fachada. En la fachada deberás detectar si se haproducido una "SinCreditoException" y hacer un rollback como viste en la sesión detransacciones del módulo EJB (context.setRollbackOnly()).

    6.3. Patrón Business Delegate (*)

    Introduce el patrón Business Delegate en la aplicación. Este será una clase javaconvencional llamada precisamente BusinessDelegate dentro del proyecto "amigos-web".El business delegate debe contener todo el código JNDI y la llamada al EJB fachada. Esdecir, la acción EnviarMensaje debe llamar al Business Delegate que a su vez, medianteJNDI, localizará la fachada y llamará a su método enviarMensajeRemoto. Lo más lógicoes que el Business Delegate encapsule esta operación dentro de un método llamadotambién "enviarMensaje"

    Patrones de diseño

    37Copyright © 2007-2008 Depto. CCIA All rights reserved.

  • Patrones de diseño

    38Copyright © 2007-2008 Depto. CCIA All rights reserved.

    1 Charla 1: Introducción a los patrones de diseño. Algunos patrones básicos1.1 Por qué patrones1.2 Patrones J2EE1.3 Singleton (GoF)1.3.1 Problema a resolver1.3.2 Discusión y beneficios1.3.3 Relación con otros patrones

    1.4 Facade (GoF)1.4.1 Problema a resolver1.4.2 Discusión y beneficios

    1.5 Factory (GoF)1.5.1 Problema a resolver1.5.2 Simple factory1.5.3 Factory method

    2 Ejercicio de la charla 1: Introducción a los patrones de diseño2.1 Refactorización basada en patrones

    3 Charla 2: Patrones para las capas de presentación y negocio3.1 Arquitecturas para la capa de presentación en aplicaciones web3.1.1 Aplicaciones JSP-céntricas3.1.2 Combinación de servlets y JSP

    3.2 Modelo-Vista-Controlador (MVC)3.2.1 Los componentes de la arquitectura: el modelo, la vista y el controlador3.2.2 Una implementación de MVC3.2.2.1 El controlador3.2.2.1.1 Configuración del web.xml3.2.2.1.2 Las acciones3.2.2.1.3 Ciclo de procesamiento

    3.2.2.2 El modelo3.2.2.3 La vista

    3.2.3 Variantes de MVC

    3.3 Algunos patrones para la capa de negocio3.3.1 Business Object3.3.2 Application Service3.3.3 Session Façade3.3.4 Business Delegate

    4 Ejercicio de la charla 2: Patrones para aplicaciones web4.1 La aplicación de bookmarks4.2 Implementación de un caso de uso con MVC4.3 Caso de uso "crear nuevo bookmark" (*)

    5 Charla 3: Patrones para aplicaciones enterprise5.1 Patrones para aplicaciones distribuidas vs. aplicaciones "locales"5.2 Fuentes bibliográficas para patrones enterprise5.3 Minimizando las llamadas remotas: Session Facade5.3.1 Problema5.3.2 Solución5.3.3 Posibles problemas

    5.4 Transfiriendo datos a los clientes: Transfer Object5.4.1 Problema5.4.2 Solución5.4.3 Posibles problemas

    5.5 Localizando servicios: Service Locator5.5.1 Problema5.5.2 Solución5.5.3 Consecuencias

    5.6 Haciendo transparentes los EJBs de negocio:Business Delegate5.6.1 Problema5.6.2 Solución5.6.3 Posibles problemas

    6 Ejercicio de la charla 3: Patrones para aplicaciones enterprise6.1 Estructura de la aplicación6.2 Patrón fachada6.3 Patrón Business Delegate (*)