En este artículo, mostramos la fortaleza de utilizar y combinar diversos patrones de diseño en la solución de un problema. Para lo que desarrollamos un ejemplo en cuya solución utilizamos los patrones Abstract Factory, Facade y Observer.
Como sabemos, los patrones de diseño, describen un problema que ocurre repetidas veces en algún contexto determinado del desarrollo de software y entregan una buena solución ya probada. Esto ayuda, a diseñar correctamente en menos tiempo, a construir soluciones reutilizables y extensibles, y facilita la documentación. Los patrones nos dicen cómo aplicar de manera eficaz la herencia, el polimorfismo y todas las ventajas que posee el paradigma orientado a objetos.
En el libro “Design Patterns: Elements of Reusable Object-Oriented Software” (Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides), los autores presentan una excelente recopilación de 23 patrones, clasificados en patrones de creación, estructura y conducta. Estos ofrecen excelentes soluciones a muchos de los problemas, que como desarrolladores de software, encontramos día con día.
Sin embargo, muchas veces, para solucionar un problema específico, no basta con aplicar un determinado patrón, sino que, de manera creativa, tenemos que combinar varios de ellos para conformar la solución. Por lo tanto, mostraremos un problema y daremos su solución, combinando varios de los patrones descritos en el libro antes mencionado.
Trabajemos entonces el siguiente problema
Se desea implementar una aplicación que verifique si un cliente es elegible para un crédito hipotecario. Dicha verificación consistiría en revisar sus cuentas bancarias y revisar su estado crediticio. Estas operaciones de verificación son complejas y varían de un país a otro. Deseamos que sea suficiente con cambiar un parámetro, para que todas las verificaciones se hagan para un determinado país. Además, que la incorporación de un nuevo país al ambiente, sea algo sencillo. Deseamos además, que la interfaz visual vaya mostrando como van avanzando cada una de esas verificaciones. Según este problema, necesitamos verificar cuentas bancarias y estado crediticio para diferentes países. Para solucionarlo, podemos utilizar el patrón Abstract Factory. Que nos permite crear una clase concreta para cada país, y trabajar con ellas de una manera totalmente uniforme, logrando que nuestra aplicación cliente se abstraiga de las complejidades de trabajar con uno u otro país.
La solución se modelaría utilizando el siguiente diagrama UML.
En el diagrama podemos ver cómo obtendremos una clase abstracta llamada AVerificador, la cual tendrá un método estático GetPaís(). A ese método le pasaremos un indicador del país que deseamos crear y nos devolverá una instancia de la clase concreta con que se modela el país, ya sea México, USA u otra. Esas clases concretas heredan de la clase abstracta AVerificador, que implementan los métodos comunes GetBanco(), GetCredito(), etcétera.
La clase Cliente declarará una variable del tipo AVerificador y la instanciará a través del método estático GetPais() de esa misma clase, obteniendo entonces una instancia del país en concreto. De esa manera, bastará con cambiar el parámetro que le pasamos al método GetPais y que indica el país con el que deseamos trabajar, para que toda la solución se enfoque en el país de nuestro interés.
El método GetBanco() devolverá instancias de las clases BancoMexico o BancoUSA, en dependencia del país con el que estemos trabajando. Esas clases implementarán la interfaz IBanco, en la que se declaran las características comunes de los bancos para todos los países. De la misma manera, el método GetCredito() devolverá instancias de las clases CreditoMexico o CreditoUSA, en dependencia del país desde donde se haya invocado. Esas dos clases implementarán la interfaz ICredito, en la que se declaran las características comunes de los créditos de todos los países.
La clase Cliente declarará variables del tipo IBanco e ICredito, a las que, se le asignarán instancias de las clases BancoMexico, BancoUSA, CreditoMexico o CreditoUSA, respectivamente. De tal manera, podrá interactuar con las clases concretas de una manera transparente, pues lo hará a través de las interfaces que ellas implementan.
Así, tenemos nuestro problema solucionado en buena medida. No obstante, el modelo puede mejorar. Sucede que la clase Cliente, va a tener que declarar un Verificador, instanciar el país en concreto, obtener su banco y su crédito e interactuar con ellos a través de sus interfaces. Lo que puede significar demasiada complejidad para un cliente; mas si deseamos implementar diversos clientes para diversas tecnologías (digamos una aplicación Windows, una aplicación Web y otra para móviles), sería mucho mejor extraer esa complejidad del cliente y colocarla en una clase de alto nivel en la capa de negocio.
Esa clase, tratará toda la lógica del patrón Abstract Factory como un subsistema, encapsulando su complejidad, ofreciendo al cliente una sencilla y única interfaz; permitiendo que el trabajo del cliente sea lo más sencillo posible.
La implementación de lo que hemos dicho, nos la da el patrón Facade. Que nos sugiere la implementación de una Fachada que interactúe con el subsistema, ofreciendo al cliente una interfaz sencilla.
La solución se modelaría utilizando el siguiente diagrama UML:
Ya tenemos un cliente sencillo y una clase que hace la verificación que deseamos. Sólo nos queda un punto por resolver. El problema inicial dice “Deseamos además, que la interfaz visual vaya mostrando como van avanzando cada una de esas verificaciones”. ¿Cómo lograr entonces que el cliente se entere que la Fachada de verificación ha hecho cada uno de los pasos?
Nos podemos apoyar en el patrón Observer, que nos dice, cómo relacionar dos clases pasando mensajes entre ellas, sin que esto conlleve al establecmiento de un acople fuerte. El patrón nos sugiere la creación de una interfaz Sujeto (ISubject) que será el sujeto observado, y una interfaz Observador (IObserver) que será quien se interese por los cambios de estado en el sujeto.
ISubject ofrecerá un método Subscribe() que reciba un parámetro de tipo IObserver, a través del cual un Observador podrá suscribirse a los eventos del sujeto. Además, ofrecerá un método Unsubscribe(), que también recibirá un IObserver para que éste se pueda desuscribir. Por último, tendrá un método Notify, en el que recorra la lista de observadores, invocándole a cada uno su método Update, para que el observador se entere que el sujeto cambió su estado y generó un evento.
Por su parte, la interfaz IObserver ofrecerá ese método Update() que será invocado por el sujeto, a través del cual, el observador se enterará del cambio de estado en el sujeto y realizado una acción al respecto.
La inclusión del patrón Observer en nuestra solución se refleja en el siguiente diagrama:
Se observa en este caso, cómo la clase Cliente implementará la interfaz IObserver, mientras que la clase FachadaVerif implementará la interfaz ISubject. A partir de ese momento, Cliente se convierte en un Observador, mientras que FachadaVerif se convierte en el sujeto observado. El Cliente entonces, se puede suscribir a los eventos de la Fachada, y ésta, cuando verifique el banco, invocará su método Notify para avisar al cliente que se ha dado un paso. Pasará lo mismo cuando revise el crédito. De tal manera el Cliente recibirá eventos a medida que se van ejecutando los diferentes pasos de la verificación, además de contar con la libertad de hacer ciertas acciones, como por ejemplo, ir avanzando una barra de progreso, entre otras.
Así finalizamos este ejemplo. En él utilizamos tres patrones: el Abstract Factory, el Facade y el Observer, para a través de su combinación, obtener la solución a nuestro problema.
Referencias
• Profesional Design Patterns in VB.NET: Building Adaptable Applications. Tom Fischer, et al. Apress, 2003.
• Design Patterns: Elements of Reusable Object Oriented Design. Erich Gamma, et al. Addison Wesley, 1995.
Eduardo Noriega de Armas es Director General del proyecto AprendaMas.Net (www.aprendamas.net). Realizó sus estudios de Licenciatura y Maestría en la Universidad Central de Las Villas, en Cuba. Ha sido profesor en las Universidades Central de Las Villas en Cuba, Universidad de Guadalajara e Instituto Tecnológico y de Estudios Superiores de Occidente (ITESO). Ha sido consultor en varias empresas y forma parte del equipo de desarrollo de la compañía Grupo Flextronics S.A. de C.V.
- Log in to post comments