Composición y variación de patrones de diseño
Preámbulo
Los veintitrés patrones de diseño presentados en este libro no constituyen una lista exhaustiva. Es posible crear nuevos patrones de diseño bien ex nihilo, o bien componiendo o adaptando patrones de diseño existentes. Estos nuevos patrones de diseño pueden tener un carácter general, a semejanza de los que hemos presentado en los capítulos anteriores, o ser específicos para un entorno de desarrollo particular.
En este capítulo vamos a mostrar tres nuevos patrones de diseño obtenidos mediante la composición y variación de patrones de diseño existentes.
El patrón de diseño Pluggable Factory
1. Introducción
Hemos presentado en un capítulo anterior el patrón de diseño Abstract Factory que permite abstraer la creación (instanciación) de productos de sus distintas familias. En este caso se crea una fábrica asociada a cada familia de productos. En el diagrama de la figura 29.1 se exponen dos productos: automóviles y scooters, descritos cada uno mediante una clase abstracta. Estos productos se organizan en dos familias: gasolina o electricidad. Cada una de las dos familias genera una subclase concreta de cada clase de producto.
Existen por tanto dos fábricas para las familias FabricaVehiculoGasolina y FabricaVehiculoElectricidad. Cada fábrica permite crear uno de los dos productos mediante los métodos apropiados.
Este patrón de diseño organiza de forma muy estructurada la creación de objetos. Cada nueva familia de productos obliga a agregar una nueva fábrica y, por tanto, una nueva clase.
De forma opuesta, el patrón de diseño Prototype presentado en el capítulo del mismo nombre proporciona la posibilidad de crear nuevos objetos de manera muy flexible.
Figura 29.1 - Ejemplo de uso del patrón de diseño Abstract Factory
La estructura del patrón de diseño Prototype se describe en la figura 29.2. Un objeto inicializado y listo para ser utilizado con capacidad de duplicarse se llama un prototipo.
El cliente dispone de una lista de prototipos que puede duplicar cuando así lo desea. Esta lista se construye dinámicamente y puede modificarse en cualquier momento a lo largo de la ejecución. El cliente puede construir nuevos objetos sin conocer la jerarquía de clases de la que provienen.
Figura 29.2 - Ejemplo de uso del patrón de diseño Prototype
La idea del patrón de diseño Pluggable Factory consiste en componer estos dos patrones de diseño para conservar por un lado la idea de creación de un producto invocando un método de la fábrica y por otro lado la posibilidad de cambiar dinámicamente la familia que se quiere crear. De este modo, la fábrica no necesita conocer las familias de objetos, el número de familias puede ser diferente para cada producto y, por último, es posible variar el producto que se quiere crear no solo...
El patrón de diseño Reflective Visitor
1. Discusión
Hemos presentado en un capítulo anterior el patrón de diseño Visitor cuyo objetivo es agregar nuevas funcionalidades a un conjunto de clases sin tener que modificar estas clases tras cada agregación. Cada nueva funcionalidad da pie a una clase de visitante que implementa esta funcionalidad incluyendo un conjunto de métodos, uno por cada clase. Todos estos métodos tienen el nombre visita seguido por el nombre de la clase para la que se implementa la funcionalidad.
No obstante para implementar el patrón de diseño Visitor, las clases que deben ser visibles requieren una ligera modificación, a saber la inclusión de un método para aceptar al visitante, método cuyo único fin es invocar al método de nombre visita seguido por el nombre de la clase a visitar. El nombre de este método es a menudo acepta o aceptaVisitante.
La figura 29.5 muestra una implementación del patrón de diseño Visitor con el objetivo de visitar una jerarquía de objetos descrita mediante el patrón de diseño Composite. Estos objetos son empresas que en ocasiones, cuando se trata de las empresas madres, poseen filiales. Las dos funcionalidades agregadas son el cálculo de los costes de mantenimiento y la posibilidad de enviar un mailing comercial a una empresa y a todas sus filiales, incluyendo a las filiales de las filiales. El método aceptaVisitante de la clase EmpresaMadre incluye un bucle foreach que solicita a cada una de las filiales que acepte a su visitante.
Figura 29.5 - Aplicación del patrón de diseño Visitor a un conjunto de empresas
El patrón de diseño Reflective Visitor es una variante del patrón de diseño Visitor que utiliza la capacidad de reflexión estructural del lenguaje de programación de modo que la implementación no requiera la inclusión del método de aceptación del visitante en las clases que deban ser visitadas. La reflexión estructural de un lenguaje de programación es su capacidad para proveer un medio de examinar el conjunto de clases que forman el programa y su contenido (atributos y métodos). La reflexión estructural existe a día de hoy en la mayor parte de lenguajes de programación orientada a objetos...
El patrón de diseño Multicast
1. Descripción y ejemplo
El objetivo del patrón de diseño Multicast es gestionar los eventos producidos en un programa para transmitirlos a un conjunto de receptores afectados. El patrón de diseño está basado en un mecanismo de suscripción de receptores en los emisores.
Queremos implementar un programa de envío de mensajes entre las direcciones (general, comercial, financiera, etc.) de un concesionario y sus empleados.
Cada empleado se puede suscribir a la dirección a la que pertenece y recibir todos los mensajes emitidos por ella. Un empleado no puede suscribirse a una dirección a la que no pertenece. Todos los empleados pueden suscribirse a la dirección general para recibir sus mensajes.
La estructura de los mensajes puede variar de una dirección a otra: desde una simple línea de texto para los mensajes comerciales, hasta un conjunto de líneas para los mensajes generales provenientes de la dirección general.
El diagrama de clases de la figura 29.8 expone la solución proporcionada por el patrón de diseño Multicast. La clase concreta Emisor introduce los elementos encargados de emitir un mensaje a un conjunto de receptores. El mensaje está tipado por la interfaz MensajeAbstracto, mientras que el receptor está tipado por la interfaz ReceptorAbstracto.
Figura 29.8 - El patrón de diseño Multicast aplicado a un sistema de mensajes
La clase Emisor presenta dos funcionalidades:
-
Gestiona un registro (una lista) de receptores con la posibilidad de suscribirse a un nuevo receptor gracias al método agrega.
-
Permite enviar un mensaje al conjunto de receptores presentes en el registro gracias al método envioMultiple.
La interfaz MensajeAbstractoInterfaz implementa la firma del método Muestra contenido, cuya función es mostrar el contenido del mensaje. La interfaz ReceptorAbstractoInterfaz implementa la firma del método recibe, cuya función es mostrar el mensaje que se acompaña eventualmente de información específica del receptor.
La clase MensajeGeneral implementa el mensaje general que se va a enviar por la dirección general. Implementa la interfaz MensajeAbstracto y, como consecuencia, el método MuestraContenido.
La clase DireccionGeneral representa a la dirección general. Conserva un enlace...