sábado, 20 de julio de 2013
lunes, 8 de julio de 2013
Patrones de Diseño
INTRODUCCIÓN.
En este
blog se explicara acerca de que es un patrón, un patrón de
diseño, su clasificación y el listado de los patrones que existen en
cada una de estas, además de ejemplos y los problemas a los
cuales darían la solución los patrones.
¿QUE ES UN PATRÓN?
Un patrón es
un tipo de sucesos u objetos recurrentes, es decir que vuelve a ocurrir o
suceder constantemente y se repite una y otra vez; un ejemplo es al realizar
cierta actividad donde todos los días seguimos una serie de pasos
para poder llevar a cabo dicha actividad.
¿QUE ES UN PATRÓN DE DISEÑO?
Un patrón de
diseño es la búsqueda a una solución a problemas comunes en el
desarrollo de software, es decir nos brinda una solución que ya ha
sido probada aplicado al desarrollo de software,
Las características
con las que debe de contar un patrón son las siguientes:
* Nombre
del patrón. Describe el nombre del problema
* El
problema (Cuando pude ser aplicado)
*
La solución (Descripción los elementos que componen el diseño, sus
relaciones, responsabilidades y colaboración).
*
Las consecuencias (Costos y beneficios).
Además de
las características que deben de contar los patrones se con la
siguiente clasificación;
*
Patrones de creación: Inicialización y configuración de los objetos.
* Patrones
estructurales: Separan la interfaz de la implementación. Se ocupan de como las
clases y objetos se agrupan, para formar estructuras más grandes.
*
Patrones de comportamiento: Más que describir objetos y clases, describen
la comunicación entre ellos.
Cabe
mencionar que para aplicar o utilizar los patrones de diseño debemos tener
conocimientos previos a la Programación Orientada a Objetos.
BUSINNES DELEGATE.
Este patrón nos puede ayudar, combinado con otros, a resolver situaciones particulares como son los siguientes:
• Cache de objetos
• Repetición de peticiones cuando un objeto remoto no está disponible (o hay un problema temporal de comunicaciones).
Este patrón es utilizado para reducir el acoplamiento entre los clientes de la capa de presentación y los servicios de negocio, además de ocultar los detalles de la implementación del servicio de negocio, así como los detalles de búsqueda y acceso de la arquitectura EJB
El Business Delegate actúa como una abstracción de negocio del lado del cliente; ya que proporciona una abstracción por lo que tanto oculta, la implementación de los servicios del negocio. Utilizando Business Delegate se reduce el acoplamiento entre los clientes de la capa de presentación y los servicios de negocio del sistema. Dependiendo de la estrategia de implementación, Business Delegate podría aislar a los clientes de la posible volatilidad en la implementación del API de los servicios de negocio. Potencialmente, esto reduce el número de cambios que se deben hacer en el código de cliente de la capa de presentación cuando cambie el API del servicio de negocio o su implementación subyacente. Business Delegate.
Aquí a continuación se muestra la estructura de este patrón.
Este patrón es utilizado en sistemas multi-capa distribuidos cuando es necesaria la invocación de métodos remotos para enviar y recibir datos entre las distintas capas del sistema.
Evita que los componentes de la capa de presentación interactúen directamente con los servicios de negocio y sean vulnerables a los cambios en la capa de negocio. Si no se empleara este patrón sería necesario exponer la implementación de la interfaz del servicio de negocio a la capa de presentación obteniendo una fuerte dependencia entre ambas capas.
Este patrón reduce el acoplamiento entre los clientes y la capa de negocio, ocultando los detalles de la implementación de los servicios de negocios y búsquedas y accesos asociados en los sistemas distribuidos.
Otras de las ventajas del uso de este patrón es la posibilidad de dotarlo de la capacidad de almacenar resultados y referencias a servicios remotos que puede mejorar considerablemente el rendimiento.
Puede utilizarse como interfaz entre distintas capas
Normalmente el Business Delegate oculta a otro patrón, el Session Façade, ocultando la tecnología utilizada en el modelo.
OBJETO COMPUESTO (COMPOSITIVE).
Este patrón es utilizado para construir objetos a partir de otros más simples, utilizando para ello la composición recursiva y una estructura de árbol.
El patrón combina objetos en estructuras de árbol para representar jerarquías de parte-todo. Permite que los clientes traten de manera uniforme a los objetos individuales y a los compuestos.
Su objetivo es componer objetos en jerarquías parte-todo y permitir a los clientes tratar objetos simples y compuestos de modo uniforme.
Necesitamos representar un conjunto de elementos de una interfaz gráfica de usuario (GUI).
Algunos de estos elementos son simples, mientras que otros están formados por varios elementos más simples. El comportamiento y/o la información que proporciona un elemento complejo están determinados por los elementos que lo componen.
La estructura de este patrón se explica a continuación.
Quienes participan para el funcionamiento de este patrón se mencionan a continuación.
Component: Declara la interfaz para los objetos de la composición, es la interfaz de acceso y manipulación de los componentes hijo e implementa algunos comportamientos por defecto.
Client: Manipula objetos a través de la interfaz proporcionada por Component.
Composite: Define el comportamiento de los componentes compuestos, almacena a los hijos e implementa las operaciones de manejo de los componentes.
Leaf: Definen comportamientos para objetos primitivos del compuesto.
COMPOSITIVE VIEW
El propósito de este patrón es crear Vistas Compuestas de varias sub-vistas de forma modular, flexible y extensible para construir vistas de páginas JSP para aplicaciones J2EE. [Sun]
Una Vista Compuesta es una vista a la que se le han agregado varias sub-vistas.
View Manager (Controlador de Vistas)
El Controlador de Vista maneja la inclusión de fragmentos de una plantilla en la Vista Compuesta. El Controlador de Vista podría ser parte de un motor de ejecución estándar de páginas JSP, en la forma de la etiqueta <jsp:include> de JSP, o podría encapsularse dentro de un helper JavaBean o una etiqueta personalizada para proporcionar una funcionalidad más robusta.
Una Vista Incluida es una sub-vista, una pieza atómica de una vista mayor. Esta vista incluida también podría ser una vista compuesta, incluyendo varias sub-vistas.
Cuando un usuario navega a través de aplicaciones gráficas los datos y el contenido entre las diferentes páginas varía, pero muchos elementos, como una cabecera común o una barra lateral permanecen intactos en todas las vistas. La estructura y disposición de cada página puede ser la misma y algunos elementos o secciones de la página pueden aparecer en varias páginas diferentes. Cuando estos elementos y grupos se codifican directamente en la aplicación se vuelve muy difícil la tarea de modificar las vistas y se puede incurrir en inconsistencias.
Las páginas Web sofisticadas presentan contenido de varias fuentes de datos, utilizando una Vista Compuesta (Composite View) formada por otras sub-vistas. Cualquier cambio realizado en una sub-vista es reflejado automáticamente en cada Vista Compuesta que la utilice.
La Vista Compuesta también maneja la disposición de sus sub-vistas y proporciona una plantilla, dando una apariencia consistente y facilidades a la hora de modificarla y mantenerla a lo largo de toda la aplicación.
Se usará el patrón Composite View cuando:
- Varias vistas compuestas utilizan sub-vistas similares.
- Las porciones atómicas del contenido de una vista cambian con frecuencia.
Consecuencias
- Cada componente de la plantilla puede incluirse dinámicamente dentro del todo y la distribución de la página puede manejarse de forma independiente del contenido.
- Esta solución es útil para la creación de vistas basadas en la inclusión y sustitución de fragmentos de plantilla modulares, tanto estáticos como dinámicos. Los diseñadores pueden hacer un prototipo de la distribución de la web, poniendo contenido estático en cada región de la plantilla. Según va progresando el desarrollo, este contenido se puede ir sustituyendo por el contenido dinámico.
- Promueve la reutilización de porciones atómicas de la vista, animando a realizar diseños modulares.
- Es apropiado utilizar este patrón para generar páginas que muestren componentes que podrían combinarse de diferentes maneras. Esto ocurre, por ejemplo, con portales que incluyan numerosas sub-vistas independientes, como noticias, información del tiempo, etc.
en una sola página. La distribución de la página se maneja y modifica de forma independiente al contenido de las sub-vistas.
- Provoca una sobrecarga en tiempo de ejecución, un precio que hay que pagar por el incremento de flexibilidad que proporciona.
Un Composite View se puede implementar siguiendo la estrategia JSP page View o bien la estrategia Servlet View.
El control de la vista se puede implementar de diferentes formas: utilizando etiquetas jsp estándar, como <jsp:include>, utilizando componentes JavaBeans.
Patrones relacionados
El patrón de vista compuesta se podría utilizar como la vista del patrón View Helper. Así la vista compuesta delega sus responsabilidades de procesamiento en sus clases de ayuda, implementadas como JavaBeans o etiquetas personalizadas. Las clases de ayuda o helpers también almacenan el modelo de datos intermedio de la vista y sirven como adaptadores de datos de negocio.
DATA ACCES OBJECT
Muchas aplicaciones del “mundo-real” de la plataforma Java 2 Enterprise Edition (J2EE) necesitan usar persistencia de datos en algún momento de su vida. Para muchas aplicaciones, el almacenamiento persistente es implementado con diferentes mecanismos, y aquí es donde se marca la diferencia entre las APIs usadas para acceder a diferentes mecanismos de almacenamiento persistente. Otras aplicaciones pueden requerir de acceso a datos que residen en sistemas separados. Por Ejemplo, la data puede residir en sistemas mainframe, en repositorios LDAP (Lightweight Directory Access Protocol), y así muchas más. Otro ejemplo es cuando la data es proveída por servicios mediante sistemas externos como Integraciones de sistemas B2B (business-to-business), un servicio de tarjetas de crédito, entre otros.
Generalmente, las aplicaciones usan componentes compartidos y distribuidos, como los entity beans para representar data persistente. Una aplicación es considerada para utilizar persistencia administrada por beans (BMP) para sus entity beans cuando éstos acceden explícitamente el almacenamiento persistente e incluyen código para acceder directamente al almacén persistente. Una aplicación con requerimientos simples puede renunciar al uso de entity beans y en cambio usar beans de sesión o servlets para acceder al almacén persistente para recibir o modificar la data. O, la aplicación podría usar entity beans con un contenedor de persistencias administrado, y entonces permitir al contenedor manipular las transacciones y detalles persistentes.
Las aplicaciones pueden usar el API JDBC para acceder a data residente en una base de datos relacional (RDBMS). El API JDBC habilita un acceso y manipulación estándar de datos en un almacenamiento persistente, como una base de datos relacional. El API JDBC habilita a las aplicaciones J2EE para usar sentencias SQL. Como sea, siempre dentro de un ambiente RDBMS, la sintaxis y el formato de las sentencias SQL puede variar dependiendo del producto de bases de datos en particular.
Existe una variación aún mayor con diferentes tipos de almacenamientos persistentes. Mecanismos de acceso, APIs soportadas y las características entre los diversos medios de almacenamientos persistentes, como los RDBMS, bases de datos orientadas a objetos, archivos planos y otros. Las aplicaciones necesitan acceder a datos desde sistemas heredados o sistemas dispares (como un mainframe, o servicios B2B) son en ocasiones candidatos directos a usar APIs propietarias. Como fuentes de datos dispares ofrecen retos a la aplicación y, potencialmente, puede crear una dependencia directa entre el código de la aplicación y el código de acceso a los datos. Cuando los componentes entity beans, beans de sesión, e incluso componentes de presentación como servlets y objetos de ayuda (helper objects) para páginas JavaServer Pages (JSP) tienen la necesidad de acceder a una fuente de datos, pueden utilizar la API adecuada para lograr la conectividad y manipular la fuente de datos. Sin embargo, como la conectividad y el código de acceso a los datos dentro de estos componentes presenta una estrecha conexión entre los componentes y la implementación de la fuente de datos. Las dependencias de código en los componentes hacen que sea difícil y tedioso el momento de migrar la aplicación de un tipo de fuente de datos a otro. Cuando se cambia la fuente de datos, lamentablemente los componentes deben ser cambiados para manejar el nuevo tipo de fuente de datos.
El patrón de diseño DAO implementa el mecanismo de acceso requerido para trabajar con la fuente de datos. La fuente de datos podría ser un almacenamiento persistente como un RDBMS, un servicio externo como un intercambio de B2B, un repositorio como una base de datos LDAP, o un servicio de negocio accesible a través de CORBA Internet Inter-ORB Protocol (IIOP) o sockets de bajo nivel. Los componentes de negocio que se basan en DAO utilizan la interfaz más simple expuesta por DAO para sus clientes. DAO oculta completamente los detalles del origen de datos de la aplicación hacia sus clientes. Debido a que la interfaz expuesta por el DAO a los clientes no cambia cuando los datos subyacentes cambian su implementación de código, este modelo permite al DAO adaptarse a los sistemas de almacenamiento sin que ello afecte a sus clientes o componentes de negocio. Esencialmente, DAO actúa como un adaptador entre el componente y la fuente de datos.
La siguiente figura muestra el diagrama de clases que representa las relaciones para el patrón DAO.
La figura a continuación contiene el diagrama de secuencia que muestra la interacción entre los distintos participantes en este patrón.
BusinessObject
El BusinessObject representa al cliente los datos. Es el objeto que requiere el acceso a la fuente de datos para obtener y almacenar datos. BusinessObject puede ser implementado como un bean de sesión, beans de entidad, o algún otro objeto Java, además de un servlet o un helper bean que accede a la fuente de datos.
DataAccessObject
El DataAccessObject es el objeto principal de este patrón. El DataAccessObject abstrae la implementación del acceso a los datos subyacentes para el BusinessObject para permitir el acceso transparente a la fuente de datos. El BusinessObject también delega la carga de datos y operaciones de almacenamiento al DataAccessObject.
DataSource
Esto representa una implementación de fuente de datos. Una fuente de datos podría ser una base de datos como un RDBMS, SGBDOO, repositorio XML,sistema de archivos planos, y así sucesivamente. Una fuente de datos también puede ser otro sistema (legacy / mainframe), servicios (servicio de B2B o una oficina de tarjetas de crédito), o algún tipo de repositorio (LDAP).
TransferObject
Esto representa un objeto de transferencia que se utiliza como soporte de datos. El DataAccessObject puede utilizar un objeto de transferencia para devolver los datos al cliente. El DataAccessObject también pueden recibir los datos del cliente en un objeto de transferencia para actualizar los datos del origen de datos.
Según lo mismo que presento acá y según lo mismo que hemos visto en clases. adjunto un ejemplo de DAO, que posee incluso lo básico de programación Orientada al Objeto:
Herencias
Interfaces
Polimorfismo
Clases Abstractas
Sobre escritura.
FAST LANE READER
Típicamente un usuario utilizará los resultados de una consulta sólo para lectura como despliegue y navegación. La implementación de un finder está dividida en dos etapas: consulta y obtención de un conjunto de llaves primarias, y ejecución de consultas para instanciar cada entity bean según su identificador, lo que es conocido como el problema de las consultas. Al utilizar CMP los container permiten realizar configuraciones para cargar datos en forma masiva reduciendo el a dos el número de consultas necesarias, sin embargo para BMP no existe una solución de similar característica.
En este caso es recomendable utilizar una implementación del finder utilizando JDBC para obtener y desplegar los datos. Para esto existen varios enfoques, ya sea utilizando Fast-Lane Reader, JDBC for Reading o un objeto más elaborado como Value List Handler que controle las búsquedas y mantenga caché de resultados.
Estos patrones significan romper las capas en la que está estructurada la aplicación, por lo que deben ser implementados con cuidado de no aumentar las dependencias entre componentes.
La intención de este patrón es implementar eficientemente casos de uso que corresponden a búsquedas que devuelven una colección de objetos
También conocido como JDBC for Reading.
La implementación de findAccountsByUserIdentifier en AccountFacadeEJB (Session Bean) devuelve una colección de AccountVOs, y se implementa delegando en la operación findByUserIdentifier de GenericAccountDAO.
La alternativa hubiese sido definir un método del tipo findAccountsByUserIdentifier en AccountHome, pero no hubiese sido tan eficiente (especialmente si Account es un EntityBean BMP).
Cuando se tienen casos de uso que corresponden a búsquedas múltiples y la eficiencia es un factor importante.
Participantes
Business Delegate
Delega las operaciones de búsqueda múltiple en un Session Facade (que usa un DAO) o directamente en un DAO
SessionFacade.
Un Session Bean que implementa las operaciones de búsqueda múltiple delegando en un DAO.
DAO Proporciona las operaciones de búsqueda accediendo directamente a la
BD
n Colaboraciones
n Un Business Delegate implementa las operaciones de búsqueda
múltiple delegando en un Session Facade (que usa un DAO) o
directamente en un DAO
Consecuencias/ Beneficios
Alternativa más eficiente que operaciones findXXX en interfaces Home que devuelven múltiples Entity Beans.
Riesgos
Información obsoleta (Idem Value Object)
Implementación
Se usa típicamente con el patrón Page-By-Page Iterator cuando las operaciones de búsqueda pueden devolver colecciones grandes (más de lo que se puede presentar en una pantalla de resultados).
Core J2EE Patterns describe el patrón Value List Handler (FastLane Reader + Page-by-Page Iterator) si los Entity Beans son de tipo CMP, los DAOs sólo necesitan tener las operaciones de búsqueda correspondientes.
Business Delegate que accede directamente al DAO
No es una arquitectura en 3 capas pura.
La implementación de las búsquedas reside en el cliente.
Necesita drivers para la BD.
Implementación (cont)
FRONT CONTROLLER
El mecanismo de manejo de peticiones de la capa de presentación debe controlar y coordinar el procesamiento de todos los usuarios a través de varias peticiones. Dichos mecanismos de control se pueden manejar de una forma centralizada o descentralizada.
El sistema requiere un punto de acceso centralizado para que el manejo de peticiones de la capa de presentación soporte la integración de los servicios del sistema, recuperación de contenidos, control de vistas, y navegación. Cuando el usuario accede a la vista directamente sin pasar un mecanismo centralizado, podrían ocurrir dos problemas:
• Se requiere que cada vista proporcione sus propios servicios del sistema, lo que normalmente resulta en duplicación de código.
• La vista de navegación se deja a los visores. Esto podría resultar en una mezcla de contenidos y navegación.
Además, el control distribuido es más difícil de mantener, ya que los cambios se tienen que realizar en numerosos lugares.
• El procesamiento de servicios del sistema comunes se completa por cada petición. Por ejemplo, el servicio de seguridad completa los chequeos de autentificación y autorización.
• La lógica se maneja mejor en una localización central en lugar de estar replicada dentro de varias vistas.
• Existen puntos de decisión con respecto a la recuperación y manipulación de los datos.
• Se utilizan varias vistas para responder a peticiones de negocio similares.
• Puede ser muy útil un punto de contacto centralizado para manejar una petición, por ejemplo, para controlar y grabar el camino de un usuario por la site.
• Los servicios del sistema y la lógica de control de vistas son relativamente sofisticados.
Usar un controlador como el punto inicial de contacto para manejar las peticiones. El controlador maneja el control de peticiones, incluyendo la invocación de los servicios de seguridad como la autentificación y autorización, delegar el procesamiento de negocio, controlar la elección de una vista apropiada, el manejo de errores, y el control de la selección de estrategias de creación de contenido.
El controlador proporciona un punto de entrada centralizado que controla y maneja las peticiones Web. Centralizando los puntos de decisión y control, el controlador también ayuda a reducir la cantidad de código Java, llamadas a scriptles, embebidos en la página JavaServer Pages (JSP).
Centralizar el control en el controlador y reduciendo la lógica de negocios en la vista permite reutilizar el código entre peticiones. Es una aproximación preferible a la alternativa de embeber código en varias vistas porque esta aproximación trata con entornos más propensos a errores, y de reutilización del tipo copiar-y-pegar.
Típicamente, un controlador se coordina con un componente dispatcher. Los dispatchersson responsable del control de la vista y de la navegación. Así, un dispatcher elige la siguiente vista por el usuario y dirige el control al recurso. Los dispatchers podrían encapsularse directametne dentro del controlador o se puede extraer en un componente separado.
Aunque el patrón Front Controller sugiere la centralización del manejo de peticiones, no limita el número de manejadores en el sistema, como lo hace Singleton. Una aplicación podría utilizar varios controladores en un sistema, cada uno mapeado a un conjunto de servicios distintos.
Estructura
La siguiente figura representa el diagrama de clases del patrón Front Controller.
Participantes y Responsabilidades
La siguiente figura representa el diagrama de la secuencia del patrón Front Controller. Muestra como el controlador maneja una petición:
Controller
El controlador es el punto de contacto inicial para manejar todas las peticiones en el sistema. El controlador podría delegar a un helper para completar la autentificación y la autorización de un usuario o para iniciar la recuperación de un contacto.
Dispatcher
Un dispatcher es el responsable del manejo de la vista y de la navegación, controlando la elección de la siguiente vista que se le presentará al usuario, y proporcionando el mecanismo para dirigir el control a ese recurso.
Un dispatcher se puede encapsular dentro de un controlador o se puede separar en otro componente que trabaja de forma coordinada. El dispatcher puede proporcionar un re-envío estático de la vista o un mecanismo de re-envío más sofisticado.
El dispatcher utiliza un objeto RequestDispatcher (soportado en la especificación Servlet) y encapsula algún procesamiento adicional.
Helper
Un helper es el responsable de ayudar a la vista o al controlador a completar su procesamiento. Así, los helpers tienen muchas responsabilidades, incluyendo la recopilación de los datos requeridos por la vista y el almacenamiento en el modelo intermedio, en cuyo caso algunas veces nos podemos referir al helper como un bean de valor. Además, los helpers pueden adaptar este modelo de datos para usarlo en la vista.
Una vista podría trabajar con cualquier número de helpers, que normalmente son componentes JavaBeans (JSP 1.0+) y etiquetas personalizadas (JSP 1.1+). Además, un helper podría representar un objeto Command o un Transformador XSL, que se utiliza en combinación con una hoja de estilos para adaptar y convertir el modelo a la forma apropiada.
View
Una Vista representa y muestra información al cliente. La vista recupera información desde el modelo. Los helpers soportan las diferentes vistas encapsulando y adaptanto el modelo de datos subyacente para usarlo en el display.
Estrategias
Hay varias estrategias para implementar un controlador.
Es un patrón de diseño que se basa en usar un controlador como punto inicial para la gestión de las peticiones. El controlador gestiona estas peticiones, y realiza algunas funciones como: comprobación de restricciones de seguridad, manejo de errores, mapear y delegación de las peticiones a otros componentes de la aplicación que se encargarán de generar la vista adecuada para el usuario. La siguiente figura muestra un esquema de ello:
Ventajas:
• Tenemos centralizado en un único punto la gestión de las peticiones
• Aumentamos la reusabilidad de código
• Mejoramos la gestión de la seguridad
Desventajas:
• La velocidad de respuesta disminuye al tener que ser procesadas las peticiones primero por el controlador.
INTERCEPTING FILTER
El mecanismo de manejo de peticiones de la capa de presentación recibe muchos tipos diferentes de peticiones, cada uno de los cuales requiere varios tipos de procesamiento. Algunas peticiones simplemente requieren su reenvió al componente manejador apropiado, mientras que otras peticiones deben ser modificadas, auditadas, o descomprimidas antes de su procesamiento posterior.
Problema:
Se requiere un pre-procesamiento y un post-procesamiento de unas peticiones o respuestas de un cliente Web.
Cuando una petición entra a una aplicación Web, normalmente debe pasar varios test de entrada antes del estado de procesamiento principal. Por ejemplo,
• ¿Se ha autentificado el cliente?
• ¿Tiene el cliente una sesión válida?
• ¿La dirección IP del cliente es de una red conocida?
• ¿Viola alguna restricción el path de la petición?
• ¿Qué codificación usa el cliente para enviar los datos?
• ¿Soportamos el tipo de navegador del cliente?
Algunos de estos chequeos son tests, que resultan en una respuesta de si o no que determina si continuará el procesamiento. Otros chequeos manipulan el stream de datos entrantes a una forma aceptable para el procesamiento.
La solución básica consiste en un serie de chequeos condicionales, si cualquiera de ellos falla la petición se aborta. Las sentencias if/else anidadas son una estrategia estándar, pero esta solución tiene fragilidad de código y un estilo de programación de copiar-y-pegar, porque el flujo del filtrado y la acción de los filtros se compila dentro de la aplicación.
La clave para solventar este problema de una forma flexible y no obstruida es tener un mecanismo simple para añadir y eliminar componentes de procesamiento, en el que cada componente completa una acción de filtrado específica.
Causas
• Procesamiento común, como un chequeo del esquema de codificación de datos o la información de login de cada petición, completo por cada petición.
• Se desea la centralización de la lógica común.
• Se debería facilitar la adición o eliminación de sevicios sin afectar a los componentes existentes, para que se puedan utilizar en gran variedad de combinaciones, como
o Logging y autentificación.
o Depuración y transformación de la salida para un cliente específico
o Descomprensión y conversión del esquema de codificación de la entrada.
Solución
Crear filtros conectables para procesar servicios comunes de una forma estándar sin requerir cambios en el código principal del procesamiento de la petición. Los filtros interceptan las peticiones entrantes y las respuestas salientes, permitiendo un pre y post-procesamiento. Podemos añadir y eliminar estos filtros a discrección, sin necesitar cambios en nuestro código existente.
Podemos, en efecto, decorar nuestro procesamiento principal con una veriedad de servicios comunes, como la seguridad, el logging, el depurado, etc. Estos filtros son componentes independientes del código de la aplicación principal, y pueden añadirse o eliminarse de forma declarativa. Por ejemplo, se podría modificar un fichero de configuración de despliegue para configurar una cadena de filtros. Cuando un cliente pide un recurso que corresponde con este mapeo de URL configurado, se procesa cada filtro de la cadena antes de poder invocar el recurso objetivo.
Estructura
La siguiente figura representa el diagrama de clases del patrón Intercepting Filter.
Participantes y Responsabilidades
La siguiente figura representa el diagrama de la secuencia del patrón Intercepting Filter.
FilterManager
El FilterManager maneja el procesamiento de filtros. Crea el FilterChain con los filtros apropiados, en el orden correcto e inicia el procesamiento.
FilterChain
El FilterChain es una collection ordenada de filtros indenpendientes.
FilterOne, FilterTwo, FilterThree
Estos son los filtros individuales que son mapeados a un objetivo. El FilterChain coordina su procesamiento.
Target
El Target es el recurso que el cliente ha solicitado.
MODELO VISTA CONTROLADOR
MVC es un patrón de diseño que fue inicialmente utilizado para construir interfaces de usuario.
El Modelo Vista Controlador (MVC) es un patrón de arquitectura de software que separa los datos y la lógica de negocio de una aplicación de la interfaz de usuario y el módulo encargado de gestionar los eventos y las comunicaciones. Para ello MVC propone la construcción de tres componentes distintos que son el modelo, la vista y el controlador, es decir, por un lado define componentes para la representación de la información, y por otro lado para la interacción del usuario. Este patrón de diseño se basa en las ideas de reutilización de código y la separación de conceptos, características que buscan facilitar la tarea de desarrollo de aplicaciones y su posterior mantenimiento.
De manera genérica, los componentes de MVC se podrían definir como sigue:
• El Modelo: Es la representación de la información con la cual el sistema opera, por lo tanto gestiona todos los accesos a dicha información, tanto consultas como actualizaciones, implementando también los privilegios de acceso que se hayan descrito en las especificaciones de la aplicación (lógica de negocio). Envía a la 'vista' aquella parte de la información que en cada momento se le solicita para que sea mostrada (típicamente a un usuario). Las peticiones de acceso o manipulación de información llegan al 'modelo' a través del 'controlador'.
• El Controlador: Responde a eventos (usualmente acciones del usuario) e invoca peticiones al 'modelo' cuando se hace alguna solicitud sobre la información (por ejemplo, editar un documento o un registro en una base de datos). También puede enviar comandos a su 'vista' asociada si se solicita un cambio en la forma en que se presenta de 'modelo' (por ejemplo, desplazamiento o scroll por un documento o por los diferentes registros de una base de datos), por tanto se podría decir que el 'controlador' hace de intermediario entre la 'vista' y el 'modelo'.
• La Vista: Presenta el 'modelo' (información y lógica de negocio) en un formato adecuado para interactuar (usualmente la interfaz de usuario) por tanto requiere de dicho 'modelo' la información que debe representar como salida.
Finalmente, la idea es lograr separar responsabilidades entre las personas que trabajan para un proyecto de desarrollo de software; es decir, descomponer el problema en módulos funcionales, (entre ellos el diseño gráfico), lo que se traduce en enfocar de una forma reduccionista la solución de un proyecto software.
Aunque se pueden encontrar diferentes implementaciones de MVC, el flujo de control generalmente es el siguiente:
1. El usuario interactúa con la interfaz de alguna manera (ej. presionando un botón, un enlace).
2. El controlador recibe (por parte de los objetos de la interfaz vista) la notificación de la acción solicitada por el usuario
3. El controlador accede al modelo, posiblemente actualizando los datos enviados por el usuario.
4. El controlador delega a los objetos de la vista la tarea de desplegar la interfaz de usuario.
5. La vista usa el modelo para generar la interfaz apropiada para el usuario
donde se refleja los cambios en el modelo.
6. En algunas implementaciones la vista no tiene acceso directo al modelo, dejando que el controlador envíe los da tos del modelo a la vista. Esta segunda es la que utilizaremos en este curso.
7. La interfaz espera por nuevas interacciones de usuario para iniciar nuevamente el ciclo.
SERVICE LOCATOR
La búsqueda y creación de servicios implican interfaces complejos y operaciones de red.
Problema
Los clientes J2EE interactúan con componentes de servicio, como componentes JavaBeans Enterprise (EJB) y Java Message Service (JMS), que proporcionan servicios de negocio y capacidades de persistencia. Para interactúar con estos componentes, los clientes deben o lcalizar el componente de servicio (referido como una operación de búsqueda) o crear un nuevo componente. Por ejemplo, un cliente EJB debe localizar el objeto home del bean enterprise, que el cliente puede utilizar para encontrar un objeto o para crear uno o más beans enterprise. De forma similar, un cliente JMS primero debe localizar la Factoría de Conexiones JMS para obtener una Conexión JMS o una Sesión JMS.
Todos los clientes de aplicaciones J2EE utilizan la facilidad JNDI para buscar y crear componentes EJB o JMS. El API JNDI permite a los clientes obtener un objeto Contexto Inicial que contiene el nombre del componente a uniones de objetos. El cliente empieza obteniendo el contexto inicial para un objeto home de un bean. El contexto inicial permanece válido mientras sea válida la sesión del cliente. El cliente proporciona el nombre registrado en JNDI del objeto requerido para obtener una referencia a un objeto administrado. En el contexto de una aplicación EJB, un objeto administrado típico es un objeto home de un bean enterprise. Para aplicaciones JMS, el objeto administrado puede ser una Factoría de Conexiones JMS (para unTopic o una Queue) o un Destino JMS (un Topic o una Queue).
Por eso, localizar un objeto servicio administrado JNDI es un tarea común para todos los clientes que necesiten acceder al objeto de servicio. Por ejemplo, es fácil ver que muchos tipos de clientes utilizan repetidamente el servicio JNDI, y que el código JNDI aparece varias veces en esos clientes. Esto resulta en una duplicación de código innecesaria en los clientes que necesitan buscar servicios.
También, crear un objeto de contexto JNDI inicial y realizar una búsqueda para objeto home EJB utiliza muchos recursos. Si varios clientes requieren de forma repetitiva el mismo objeto home de un bean, dicha duplicación de esfuerzos puede impactar de forma negativa en el rendimiento de la aplicación.
Examinemos el proceso de búsqueda y creación de varios componentes J2EE.
1. La búsqueda y creación de Beans Enterprise trata sobre lo siguiente:
o Una correcta configuración del entorno JNDI para que se conecte con el servicio de nombrado y directorio utilizado por la aplicación. Esta configuración proporciona la localización del servicio de nombrado y las credenciales de autentificaciones necesarias para acceder a ese servicio.
o Entonces el servicio JNDI puede proporcionar al cliente un contexto inicial que actúa como un almacen para las uniones de componentes nombre-a-objeto. El cliente solicita a este contexto inicial que busque el objeto EJBHome del bean enterprise requerido proporcionando un nombre JNDI para ese objeto EJBHome.
o Encontrar el objeto EJBHome utilizando el contexto de búsqueda inicial
o Después de obtener el objeto EJBHome, crea, elimina o encuentra el bean enterprise utilizando los métodos create, move o find (solo para beans de entidad) del objeto EJBHome.
2. La búsqueda y creación de componentes JMS (Topic, Queue, QueueConnection, QueueSession, TopicConnection, TopicSession, etc.) implica los siguientes pasos. Observa que en estos pasos, Topic se refiere al modelo de mensajería publica/subscribe y que se refiere al modelo de mensajería punto-a-punto.
o Una correcta configuración del entorno JNDI para que se conecte con el servicio de nombrado y directorio utilizado por la aplicación. Esta configuración proporciona la localización del servicio de nombrado y las credenciales de autentificaciones necesarias para acceder a ese servicio.
o Obtener el contexto inicial para el proveedor de servicio JMS desde el servicio de nombrado JNDI.
o Utilizar el contexto inicial para obtener un Topic o un Queue suministrando el nombre JNDI para ese Topic o Queue. Ambos son objetos JMSDestination.
o Utilizar el contexto inicial para obtener un TopicConnectionFactory o unQueueConnectionFactory suministrando el nombre JNDI para la factoría adecuada.
o Usar el TopicConnectionFactory para obtener un TopicConnection o elQueueConnectionFactory para obtener un QueueConnection.
o Utilizar el TopicConnection para obtener un TopicSession o elQueueConnection para obtener un QueueSession.
o Utilizar el TopicSession para obtener un TopicSubscriber o unTopicPublisher para el Topic Requerido. Utilizar el QueueSession para obtener un QueueReceiver o un QueueSender para el Queue requerido.
El proceso de búsqueda y creación de componentes implica una implementación de una factoria de contextos suministrada por un vendedor. Esto introduce dependencias del vendedor en los clientes de la aplicación que necesitan utilizar la facilidad de búsqueda JNDI para localizar beans enterprise y componentes JMS.
Causas
• Los clientes EJB necesitan utilizar el API JNDI para buscar objetos EJBHome utilizando el nombre registrado del bean enterprise.
• Los clientes JMS necesitan utilizar el API JNDI para buscar componentes JMS utilizando los nombres registrados en JDNI para esos componentes JMS.
• La factoría de contextos utilizada para la creación del contexto inicial JNDI la proporciona el vendedor del proveedor del servicio y por lo tanto es dependiente del vendedor. La factoría de contexto también es dependiente del tipo de objeto que se está buscando. El contexto para una JMS es diferente que el contexto para EJBs, con diferentes proveedores.
• La búsqueda y creación de componentes de servicio podría ser compleja y se podría utilizar repetidamente en múltiples clientes en la aplicación.
• La creación del contexto inicial y el servicio de búsqueda de objetos, si se utiliza frecuentemente, puede consumir muchos recursos e impactar en el rendimiento de la aplicación. Esto es especialmente cierto si los clientes y los servicios están localizados en diferentes capas.
• Los clientes EJB podrían necesitar reestablecer conexiones a un ejemplar de bean enterprise al que se ha accedido préviamente, teniendo solamente su objeto Handle.
Solución
Utilizar un objeto Service Locator para abstraer toda la utilización JNDI y para ocultar las complejidades de la creación del contexto inicial, de busqueda de objetoshome EJB y de re-creación de objetos EJB. Varios clientes pueden reutilizar el objetoService Locator para reducir la complejidad del código, proporcionando un punto de control, y mejorando el rendimiento proporcionando facilidades de caché.
Este patrón reduce la complejidad del cliente que resulta de las dependencias del cliente y de la necesidad de realizar los procesos de búsqueda y creación, que consumen muchos recursos. Para eliminar estos problemas, este patrón proporciona un mecanismo para abstraer todas las dependencias y detalles de red dentro del Service Locator.
Estructura
La siguiente figura muestra el diagrama de clases que representa las relaciones para el patrónService Locator.
Participantes y Responsabilidades
La siguiente figura contiene el diagrama de secuencia que muestra la interacción entre los distintos participantes en el patrón Service Locator.
Client
Este es el cliente del Service Locator. El cliente es un objeto que normalmente requiere acceder a objetos de negocio como un Business Delegate.
Service Locator
El Service Locator abstrae el API de los servicios de búsqueda (nombrado), las dependencias del vendedor, las complejidades de la búsqueda, y la creación de objetos de negocio, y proporciona un interface simple para los clientes. Esto reduce la complejidad del cliente. Además, el mismo cliente y otros clientes pueden reutilizar el Service Locator.
InitialContext
El objeto InitialContext es el punto de inicio para los procesos de búsqueda y creación. Los proveedores de servicio proporcionan el objeto context, que varía dependiendeo del tipo de objetos de negocio proporcionados por el servicio de búsqueda y creación del Service Locator. Un Service Locator que proporciona los servicios para varios tipos de objetos de negocio (como beans enterprise, componentes JMS, etc.) utiliza varios tipos de objetoscontext, cada uno obtenido de un proveedor diferente (por ejemplo, el proveedor de contexto para un servidor de aplicaciones EJB podría ser diferente del proveedor de contexto para un servicio JMS).
ServiceFactory
El objeto ServiceFactory representa un objeto que proporciona control del ciclo de vida para objetos BusinessService. El objeto ServiceFactory para beans enterprise es un objetoEJBHome. El ServiceFactory para componentes JMS puede ser un objetoConnectionFactory, como un TopicConnectionFactory o un QueueConnectionFactory.
BusinessService
BusinessService es un rol que cumple el servicio que el cliente ha solicitado. El objetoBusinessService se crea, se busca o se elimina mediante el objeto ServiceFactory. El objeto BusinessService en el contexto de una aplicación EJB es un bean enterprise. El objeto BusinessService en el contexto de una aplicación JMS puede ser unTopicConnection o un QueueConnection. TopicConnection y QueueConnection se pueden entonces utilizar para producir un objeto JMSSession, como un TopicSession o unQueueSession respectivamente.
EJB Service Locator
El Service Locator para componentes bean enterprise utiliza objetos EJBHome, como unBusinessHome en el rol del ServiceFactory. Una vez obtenido el objeto EJBHome, se puede almacenar en el ServiceLocator para un uso posterior y evitar así otra búsqueda JNDI cuando el cliente necesite de nuevo el objeto home. Dependiendo de la implementación, el objetohome puede ser devuelto al cliente, que puede entonces utilizarlo para buscar, crear o eliminar beans enterprise. Por otro lado, el ServiceLocator puede retener (en el caché) el objetohome y ganar la responsabilidad adicional de hacer de proxy de todas las llamadas de clientes al objeto home. En la siguiente figura podemos ver el diagram de clases para la Estrategia EJB Service Locator:
La interación entre todos los participantes en un Service Locator para un bean enterprise se puede ver en la siguiente figura:
JMS Queue Service Locator
Esta estrategia se aplica para los requerimientos de mensajería punto-a-punto. El Service Locator para componentes JMS utiliza objetos QueueConnectionFactory en el rol delServiceFactory. Se busca el QueueConnectionFactory utilizando su nombre JNDI. ElServiceLocator puede almacenar (en el caché) el objeto QueueConnectionFactory para un uso posterior. Esto evita repetidas llamadas JNDI para buscarlo cuando el cliente lo necesite de nuevo. Por otro lado, el ServiceLocator podría enviar el QueueConnectionFactory al cliente. Entonces, el cliente puede utilizarlo para crear una QueueConnection. Se necesita unaQueueConnection para poder obtener una QueueSession o para crear un Message, unQueueSender (para enviar mensajes a la cola), o un QueueReceiver (para recibir mensajes de la cola). En la siguiente figura podemos ver el diagrama de clases para esta estrategia. En este diagrama, La cola es un objeto JMS Destination registrado como un objeto JNDI-administered que representa la cola. El objeto Queue se puede obtener directamente desde el contexto buscándolo por su nombre JNDI.
La interacción entre los participantes en un Service Locator para mensajería punto-a-punto utilizando Queues JMS se puede ver en la siguiente figura:
JMS Topic Service Locator
Esta estraregia es aplicable para requerimientos de mensajeria publica/subscribe. El Service Locator para componentes JMS utiliza objetos TopicConnectionFactory en el rol delServiceFactory. Se busca el objeto TopicConnectionFactory utilizando sun nombre JNDI. El TopicConnectionFactory se puede almacenar (en el caché) mediante el ServiceLocatorpara su uso posterior. Esto evita repetidas llamadas JNDI para buscarlo cuando el cliente lo necesite de nuevo. Por otro lado, el ServiceLocator podría enviar elTopicConnectionFactory al cliente. Entonces el cliente puede utilizarlo para crear unaTopicConnection. Se necesita una TopicConnection para poder obtener unaTopicSession o para crear un Message, un TopicPublisher (para publicar un menaje para un topic), o un TopicSubscriber (para subscribirse a un topic). En la siguiente figura podemos ver el diagrama de clases para la estrategia JMS Topic Service Locator. En este diagrama, el Topic es un objeto JMS Destination registrado como un objeto adiministrado JNDI que representa el topic. El objeto Topic se puede obtener directamente desde el contexto buscándolo por su nombre JNDI.
La interacción entre los participantes en un Service Locator para mensajería pubicar/subscribirutilizando Topics JMS se puede ver en la siguiente figura:
Combined EJB and JMS Service Locator
Estas estrategias para EJB y JMS se pueden utilizar para proporcionar implementaciones independientes de Service Locator, ya que los clientes para EJB y JMS podría ser más o menos mutuamente exclusivos. Sin embargo, si hay la necesidad de combinar estas estrategias, es posible hacerlo pafra proporcionar el Service Locator para todos los objetos bean enterprise y componentes JMS.
Type Checked Service Locator
Los dos últimos diagramas proporcionan facilidades de búsqueda pasándole el nombre en el servicio de búsqueda. Para una búsqueda de un bean enterprise, el Service Locator necesita una clase como parámetro del método PortableRemoteObject.narrow(). El Service Locator puede proporcionar un método getHome(), que acepta como argumento el nombre del servicio JNDI y el nombre de la clase del objeto EJBHome del bean enterprise. Utilizando este método de pasar nombres en servicios JNDI y clases de objetos EJBHome se pueden provocar errores en los clientes. Otra aproximación es definir estáticamente los servicios en elServiceLocator, en lugar de pasarlos como parámetros string, el cliente los pasa como constantes.
Esta estrategia tiene inconvenientes. Reduce la flexibilidad de la búsqueda, que está en la estrategia Services Property Locator, pero añade chequeo de tipos en el paso de una constante al método ServiceLocator.getHome().
Service Locator Properties
Esta estrategia ayuda a corregir los inconvenientes de la estrategia anterior. Aquí se sugiere el uso de ficheros de propiedades y/o descriptores de ficheros para especificar los nombres JNDI y los nombres de las clases EJBHome. Para los clientes de la capa de presentación, dichas propiedades se pueden especificar en los descriptores de despliegue de la capa de presentación o en ficheros de propiedades. Cuando la capa de presentación accede a la capa de negocio, normalmente utiliza el patrón Business Delegate.
El patrón Business Delegate interactúa con el Service Locator para localizar los componentes de negocio. Si la capa de presentación carga las propiedades durante la inicialización y puede proporcionar un servicio para manejar los nombres JNDI y los nombres de las clases EJB para los beans enterprise requeridos, el Business Delegate podría solicitar a este servicio que los obtuviera. Una vez que el Business Delegate tiene el nombre JNDI y el nombre de la claseEJBHome, puede pedirle al Service Locator el EJBHome pasándole estas propiedades como argumentos.
Entonces el Service Locator puede utilizar el método Class.forName(EJBHome ClassName)para obtener el objeto EJBHome y utilizar el método Portable RemoteObject.narrow() para forzar el objeto, según se verá en el método getHome() en el ejemplo de ServiceLocator. Lo único que cambia es de donde vienen los nombres JNDI y los objetos Class . Por lo tanto, esta estrategia evita introducir en el código los nombres JNDI y proporciona flexibilidad para su despliegue.
SESSION FACADE
El patrón fachada viene motivado por la necesidad de estructurar un entorno de programación y reducir su complejidad con la división en subsistemas, minimizando las comunicaciones y dependencias entre éstos.
Se aplicará el patrón fachada cuando se necesite proporcionar una interfaz simple para un subsistema complejo, o cuando se quiera estructurar varios subsistemas en capas, ya que las fachadas serían el punto de entrada a cada nivel. Otro escenario proclive para su aplicación surge de la necesidad de desacoplar un sistema de sus clientes y de otros subsistemas, haciéndolo más independiente, portable y reutilizable (esto es, reduciendo dependencias entre los subsistemas y los clientes).
Se puede ver en la siguiente figura:
A continuación, se muestra un ejemplo:
Fachada (Facade): conoce qué clases del subsistema son responsables de una determinada petición, y delega esas peticiones de los clientes a los objetos apropiados del subsistema.
Subclases (ModuleA, ModuleB, ModuleC...): implementan la funcionalidad del subsistema. Realizan el trabajo solicitado por la fachada. No conocen la existencia de la fachada.
Los clientes que se comunican con el subsistema enviando peticiones al objeto Fachada, el cual las reenvía a los objetos apropiados del subsistema.
Los objetos del subsistema realizan el trabajo final ,y la fachada hace algo de trabajo para pasar de su interfaz a las del subsistema.
Los clientes que usan la fachada no tienen que acceder directamente a los objetos del subsistema.
La principal ventaja del patrón fachada consiste en que para modificar las clases de los subsistemas, sólo hay que realizar cambios en la interfaz/fachada, y los clientes pueden permanecer ajenos a ello. Además, y como se mencionó anteriormente, los clientes no necesitan conocer las clases que hay tras dicha interfaz.
Como inconveniente, si se considera el caso de que varios clientes necesiten acceder a subconjuntos diferentes de la funcionalidad que provee el sistema, podrían acabar usando sólo una pequeña parte de la fachada, por lo que sería conveniente utilizar varias fachadas más específicas en lugar de una única global.
Uno de los patrones relacionados más directamente es el singleton, dado que en determinadas ocasiones las fachadas pueden ser instancias únicas.
Otros patrones que guardan una cierta relación con el patrón fachada son los GRASP (General Responsibility Assignment Software Patterns), los cuales no son patrones de diseño, sino buenas prácticas que guían al desarrollador para encontrar los patrones de diseño, que son más concretos. Uno de los patrones GRASP es un controlador que actúa como punto de entrada en la capa lógica, lo que se puede comparar perfectamente con el uso del patrón fachada.
Problema: Un cliente necesita acceder a parte de la funcionalidad de un sistema más complejo.
• Definir una interfaz que permita acceder solamente a esa funcionalidad.
Problema: Existen grupos de tareas muy frecuentes para las que se puede crear código más sencillo y legible.
• Definir funcionalidad que agrupe estas tareas en funciones o métodos sencillos y claros.
Problema: Una biblioteca es difícilmente legible.
• Crear un intermediario más legible.
Problema: Dependencia entre el código del cliente y la parte interna de una biblioteca.
• Crear un intermediario y realizar llamadas a la biblioteca sólo o, sobre todo, a través de él.
Problema: Necesidad de acceder a un conjunto de APIs que pueden además tener un diseño no muy bueno.
• Crear una API intermedia, bien diseñada, que permita acceder a la funcionalidad de las demás.
Problema: Muchas clases cliente quieren usar varias clases servidoras, y deben saber cuál es exactamente la que le proporciona cada servicio. El sistema se volvería muy complejo, porque habría que relacionar todas las clases cliente con todas y cada una de las clases servidoras.
• Crear una o varias clases Facade, que implementen todos los servicios, de modo que o todos los clientes utilicen esa única clase, o que cada grupo de clientes use la fachada que mejor se ajuste a sus necesidades.
El problema a solucionar de este patrón es el de crear diferente familias de objetos, como por ejemplo la creación de interfaces graficas de distintos tipos (ventana, botón, menú, etc.).
Para esto debemos crear diferentes objetos, todos pertenecientes a la misma familia. Por ejemplo: podemos tomar como referencia las bibliotecas que nos sirven para crear interfaces gráficas que suelen utilizar este patrón y cada familia sería un sistema operativo distinto. Así pues, el usuario declara un Botón, pero de forma más interna lo que está creando es un BotónWindows o un BotónLinux, por ejemplo.
El problema que intenta solucionar este patrón es el de crear diferentes familias de objetos.
Subclases (ModuleA, ModuleB, ModuleC...): implementan la funcionalidad del subsistema. Realizan el trabajo solicitado por la fachada. No conocen la existencia de la fachada.
Los clientes que se comunican con el subsistema enviando peticiones al objeto Fachada, el cual las reenvía a los objetos apropiados del subsistema.
Los objetos del subsistema realizan el trabajo final ,y la fachada hace algo de trabajo para pasar de su interfaz a las del subsistema.
Los clientes que usan la fachada no tienen que acceder directamente a los objetos del subsistema.
La principal ventaja del patrón fachada consiste en que para modificar las clases de los subsistemas, sólo hay que realizar cambios en la interfaz/fachada, y los clientes pueden permanecer ajenos a ello. Además, y como se mencionó anteriormente, los clientes no necesitan conocer las clases que hay tras dicha interfaz.
Como inconveniente, si se considera el caso de que varios clientes necesiten acceder a subconjuntos diferentes de la funcionalidad que provee el sistema, podrían acabar usando sólo una pequeña parte de la fachada, por lo que sería conveniente utilizar varias fachadas más específicas en lugar de una única global.
Uno de los patrones relacionados más directamente es el singleton, dado que en determinadas ocasiones las fachadas pueden ser instancias únicas.
Otros patrones que guardan una cierta relación con el patrón fachada son los GRASP (General Responsibility Assignment Software Patterns), los cuales no son patrones de diseño, sino buenas prácticas que guían al desarrollador para encontrar los patrones de diseño, que son más concretos. Uno de los patrones GRASP es un controlador que actúa como punto de entrada en la capa lógica, lo que se puede comparar perfectamente con el uso del patrón fachada.
Problema: Un cliente necesita acceder a parte de la funcionalidad de un sistema más complejo.
• Definir una interfaz que permita acceder solamente a esa funcionalidad.
Problema: Existen grupos de tareas muy frecuentes para las que se puede crear código más sencillo y legible.
• Definir funcionalidad que agrupe estas tareas en funciones o métodos sencillos y claros.
Problema: Una biblioteca es difícilmente legible.
• Crear un intermediario más legible.
Problema: Dependencia entre el código del cliente y la parte interna de una biblioteca.
• Crear un intermediario y realizar llamadas a la biblioteca sólo o, sobre todo, a través de él.
Problema: Necesidad de acceder a un conjunto de APIs que pueden además tener un diseño no muy bueno.
• Crear una API intermedia, bien diseñada, que permita acceder a la funcionalidad de las demás.
Problema: Muchas clases cliente quieren usar varias clases servidoras, y deben saber cuál es exactamente la que le proporciona cada servicio. El sistema se volvería muy complejo, porque habría que relacionar todas las clases cliente con todas y cada una de las clases servidoras.
• Crear una o varias clases Facade, que implementen todos los servicios, de modo que o todos los clientes utilicen esa única clase, o que cada grupo de clientes use la fachada que mejor se ajuste a sus necesidades.
El problema a solucionar de este patrón es el de crear diferente familias de objetos, como por ejemplo la creación de interfaces graficas de distintos tipos (ventana, botón, menú, etc.).
Para esto debemos crear diferentes objetos, todos pertenecientes a la misma familia. Por ejemplo: podemos tomar como referencia las bibliotecas que nos sirven para crear interfaces gráficas que suelen utilizar este patrón y cada familia sería un sistema operativo distinto. Así pues, el usuario declara un Botón, pero de forma más interna lo que está creando es un BotónWindows o un BotónLinux, por ejemplo.
FABRICA ABSTRACTA (ABSTRAC FACTORY)
El problema que intenta solucionar este patrón es el de crear diferentes familias de objetos.
La estructura típica del patrón Abstract Factory es la siguiente:
• Cliente: La clase que llamará a la factoría adecuada ya que necesita crear uno de los objetos que provee la factoría, es decir, Cliente lo que quiere es obtener una instancia de alguno de los productos (ProductoA, ProductoB).
• AbstractFactory: Es la definición de la interfaces de las factorías. Debe de proveer un método para la obtención de cada objeto que pueda crear. ("crearProductoA()" y "crearProductoB()")
• Factorías Concretas: Estas son las diferentes familias de productos. Provee de la instancia concreta de la que se encarga de crear. De esta forma podemos tener una factoría que cree los elementos gráficos para Windows y otra que los cree para Linux, pudiendo poner fácilmente (creando una nueva) otra que los cree para MacOS, por ejemplo.
• Producto abstracto: Definición de las interfaces para la familia de productos genéricos. En el diagrama son "ProductoA" y "ProductoB". En un ejemplo de interfaces gráficas podrían ser todos los elementos: Botón, Ventana, Cuadro de Texto, Combo... El cliente trabajará directamente sobre esta interfaz, que será implementada por los diferentes productos concretos.
• Producto concreto: Implementación de los diferentes productos. Podría ser por ejemplo "BotónWindows" y "BotónLinux". Como ambos implementan "Botón" el cliente no sabrá si está en Windows o Linux, puesto que trabajará directamente sobre la superclase o interfaz.
Un ejemplo muy sencillo y ademas muy conocido es el de la pizeria.
Supongamos que disponemos de una cadena de pizzerías. Para crear pizzas disponemos de un método abstracto en la clase Pizzería que será implementada por cada subclase de Pizzería.
abstract Pizza crearPizza()
Concretamente se creará una clase PizzeríaZona por cada zona, por ejemplo la Pizzería de New York sería PizzeriaNewYork y la de Californía PizzeríaCalifornia que implementarán el método con los ingredientes de sus zonas.
Las pizzas son diferentes según las zonas. No es igual la pizza de New York que la pizza de California. Igualmente, aunque usarán los mismos ingredientes (tomate, mozzarella...) no los obtendrán del mismo lugar, cada zona los comprará donde lo tenga más cerca. Así pues podemos crear un método creador de Pizza que sea
Pizza(FactoriaIngredientes fi);
Como vemos utilizamos la factoría abstracta (no las concretas de cada zona, como podría ser IngredientesNewYork o IngredientesCalifornia). Pizza podrá obtener los ingredientes de la factoría independientemente de donde sea. Sería fácil crear nuevas factorías y añadirlas al sistema para crear pizzas con estos nuevos ingredientes. Efectivamente, en este ejemplo cliente es Pizza y es independiente de la Factoría usada.
El creador de la Pizza será el encargado de instanciar la factoría concreta, así pues los encargados de instanciar las factorías concretas serán las pizzerías locales. En PizzeríaNewYork podemos tener el método crearPizza() que realice el siguiente trabajo:
Pizza crearPizza() {
FactoríaIngredientes fi = new IngredientesNewYork();
Pizza pizza = new Pizza(fi); // Uso de la factoría
pizza.cortar();
pizza.empaquetar();
return pizza;
}
Como conclusión podemos observar que gracias a la factoría de ingredientes crear una nueva zona, por ejemplo una pizzería en Barcelona, no nos implicaría estar modificando el código existente, solo deberemos extenderlo (uno de los pilares de la Ingeniería del software) ya crearíamos la subclase de Pizzería: PizzeríaBarcelona que al instanciar la factoría solo debería escoger la factoría de Barcelona. Obviamente se debería crear la factoría de Barcelona que se encargaría de crear los productos obtenidos de Barcelona. Así que en ningún momento modificamos las pizzerías existentes, la superclase pizzería o las otras factorías o productos, solo creamos nuevas clases.
Caso de ejemplo
En el siguiente ejemplo seguro que nos queda todo un poco más claro. Como puede verse se trata de proporcionar 2 tipos de arquitecturas para la creación de componentes visuales, uno con Motif y el otro con WxWidgets, los productos a crear son controles de Imagen y Texto:
Conclusiones
Tal y como puede apreciarse, si en algún momento tenemos que expandir nuestro sistema, esto se puede hacer fácilmente y sobre todo de manera desacoplada:
• Expandiendo por arquitectura: si queremos dar cabida a un nuevo framework gráfico, no tendremos más que crear una nueva fábrica concreta que construya los productos para la nueva arquitectura, así como crear una particularización de dicha arquitectura para cada producto. El cliente no necesita cambiar en nada, dado que los interfaces de construcción y de manejo del producto no se han alterado.
• Expandiendo por producto: si lo que queremos es añadir otro producto (por ejemplo una ventana, un botón, …), sólo tendremos que crear el Producto abstracto nuevo, así como sus clases concretas para cada arquitectura, y añadir un nuevo método para crear dicho producto en el interfaz de la fábrica abstracta e implementarlo en las clases de fábricas concretas. En este caso el cliente obviamente cambia dado que hay un nuevo producto que puede utilizar.
MÉTODO DE FABRICACIÓN (FACTORY METHOD)
Separar la clase que crea los objetos, de la jerarquía de objetos a instanciar.
Ventajas
– Centralización de la creación de objetos
– Facilita la escalabilidad del sistema
– El usuario se abstrae de la instancia a crear
Parte del principio de que las subclases determinan la clase a implementar.
consiste en utilizar una clase constructora (al estilo del Abstract Factory) abstracta con unos cuantos métodos definidos y otro(s) abstracto(s): el dedicado a la construcción de objetos de un subtipo de un tipo determinado. Es una simplificación del Abstract Factory, en la que la clase abstracta tiene métodos concretos que usan algunos de los abstractos; según usemos una u otra hija de esta clase abstracta, tendremos uno u otro comportamiento.
Las clases principales en este patrón son el creador y el producto. El creador necesita crear instancias de productos, pero el tipo concreto de producto no debe ser forzado en las subclases del creador, porque las posibles subclases del creador deben poder especificar subclases del producto para utilizar.
La solución para esto es hacer un método abstracto (el método de la fábrica) que se define en el creador. Este método abstracto se define para que devuelva un producto. Las subclases del creador pueden sobrescribir este método para devolver subclases apropiadas del producto...
Otros Patrones con los que está relacionado
Abstract factory: El patrón Factory Method es útil para construir objetos individuales para un
propósito específico sin que la petición de construcción conozca las clases específicas que serán
instanciadas. Si se necesita crear un conjunto de algunos objetos relacionados o dependientes,
entonces el patrón Abstract Factory es más apropiado para este uso.
Template Method: es a menudo utilizado con el patrón Factory Method.
Prototype: proporciona un modo alternativo para que un objeto pueda trabajar con otros objetos sin conocer los detalles de su construcción. Este específica la clase de objetos a crear usando una instancia prototípica, y creando los objetos mediante una copia de este prototipo.
Problema al que es aplicable
• Cuando una clase no puede adelantar las clases de objetos que debe crear.
• Cuando una clase pretende que sus subclases especifiquen los objetos que ella crea.
• Cuando una clase delega su responsabilidad hacia una de entre varias subclases
auxiliares y queremos tener localizada a la subclase delegada.
Este patron debe ser utilizado cuando:
• Una clase no puede anticipar el tipo de objeto que debe crear y quiere que sus subclases especifiquen dichos objetos.
• Hay clases que delegan responsabilidades en una o varias subclases. Una aplicación es grande y compleja y possee muchos patrones creacionales.
Creator: declara el método de fabricación(creacion), que devuelve un objeto de tipo Product.
ConcretCreator: redefine el método de fabricación para devolver un producto.
ProduictoConcreto: es el resultado final. El creador se apoya en sus subclases para definir el método de fabricación que devuelve el objeto apropiado.
Suscribirse a:
Comentarios (Atom)






















