Federico Alemany
Patrones de Diseño - GoF: Gang of Four
Escrito por Federico Alemany - 27 de diciembre de 2014
Los patrones de diseño que se presentan en este articulo fueron escritos y presentados por cuatro autores ("la pandilla de los cuatro"), y por eso se los conoce con este nombre.

El ejemplo que se aborda en la descripción de estos patrones, es el mismo que se utilizó para explicar los patrones GRASP, un ejemplo de una venta (en un supermercado, por ejemplo). La explicación de cada patrón está lejos de ser un análisis exhaustivo, pero se pretende dar a entender cual es el problema básico que trata de resolver cada uno de ellos.

Adaptador: el patrón adaptador, es una especialización del patrón GRASP "polimorfismo". En el ejemplo de la venta, supongamos que las distintas formas de pago disponibles (débito, crédito, efectivo, etc) deben conectarse a diferentes sistemas (VISA para las tarjetas de crédito, y el sistema bancario para débito). Para ello, podríamos utilizar una interfaz "Pago_Interface" que implemente un método pagar(). Luego, podríamos crear una clase distinta para cada forma de pago (Pago_Visa, Pago_Master, Pago_débito, etc) y hacer que estas clases implementen esta interfaz. Con esto, logramos tener la seguridad que, independientemente del tipo de pago, nuestra clase "Venta" pueda enviar un mensaje "pagar()" con la seguridad que sera resuelto según la forma de pago elegida.

Este patrón de diseño es, en realidad, la aplicación de los siguientes patrones:
- Variaciones protegidas: debido a que las variaciones que tengan lugar en las clases de pago particulares, no afectan al sistema, ya que existen clases “intermedias” o “adaptadoras” que nos ofrecen una interfaz estable.
- Polimorfismo: debido a que clases diferentes pueden responder a un mismo mensaje, aunque la forma de implementarlo sean sustancialmente distintas.
- Indirección: al añadir un objeto adaptador, lo que se logra realmente es un nivel de indirección.
- Bajo acoplamiento: por consecuencia de la aplicación de las tres anteriores.

Factoría: Este patrón revela un nuevo problema a la hora de diseñar objetos. En el ejemplo anterior, introdujimos una clase “Adaptador”, por motivos que ya se explicaron. Pero, quien debe ser el responsable de crear dicho objeto durante la ejecución? La respuesta a esta pregunta la ofrece el patrón “factoría”, es decir, una clase cuya única función es crear objetos. “...Los objetos factoría ofrecen la ventaja de separar la responsabilidad de la creación en diferentes objetos cohesivos de apoyo y ocultan la lógica de la creación...” (UML y Patrones). Para el ejemplo anterior, un objeto factoría puede ser el responsable de responder a un método “obtener_adaptador_pago()”, devolviendo un objeto capaz de procesar el tipo de pago elegido en la venta.



Singleton: el patrón "singleton" resuelve la siguiente pregunta: en el ejemplo anterior, quien crea la factoría de pagos? Es decir, cuando pensamos en el ejemplo anterior, suponemos una clase, que nos devuelve un adaptador de pagos, mediante un método getAdaptadorPago(). Para que esto suceda, tiene que existir una instancia de FactoriaDePagos para enviarle el mensaje.
La factoría debería ser una y solo una (que sea la encargada de devolvernos múltiples instancias de adaptadores de pago).
Esto se logra a través del patrón "Singleton", creando un método ESTÁTICO obtenerFactoria().
Este método, al ser estático, podría ser llamado desde cualquier otra clase que necesite un adaptador de pago de la siguiente manera:
Factoria.getInstancia().getAdaptadorPago()
"Notese lo conciso que puede ser un diseñador en una conversación o en la documentación cuando hay un conocimiento común de los patrones. Puedo decir "Para resolver el problema de tener diversas interfaces para los servicios externos, podemos utilizar Adaptadores generados desde una Factoría Singleton..." (UML y Patrones). Así, es mas fácil comunicar nuestras ideas con otros desarrolladores sin entrar a explicar detalles menores.


Estrategia: Este patrón utiliza el polimorfismo y las interfaces para lograr variaciones protegidas. La idea básica es crear varias clases distintas que implementen una interfaz, con un método común y polimórfico, de tal manera, que pueda instanciarse alguna de las clases, pero independientemente de cual, pueda responder a dicho mensaje. Un ejemplo de este patrón, podría ser la forma en que se realizan los pagos.
Podríamos crear varias clases Pago (PagoDebito, PagoCredito, PagoCheque, PagoEfectivo, etc), todas ellas con un método concretar() (obviamente para concretar el pago de la venta).


interface iPago{
public function concretar();
}
class PagoCredito implements iPago{ … }


La estrategia, tiene que ver con poder elegir que clase instanciar bajo demanda. Es decir, en una venta, podría decidirse pagar con efectivo, para lo cual sería deseable instanciar un objeto de clase PagoEfectivo, y a la siguiente venta, instanciar otro de tipo PagoDebito. Esto nos ofrece varias ventajas, por ejemplo, la posibilidad de agregar una nueva forma de pago, sin afectar en lo mas mínimo al resto de las clases (bajo acoplamiento). Además, las funciones propias de cada tipo de pago permanecen agrupadas en clases especializadas (alta cohesión), permitiendo variar la implementación de un tipo especifico de pago, sin afectar las clases que utilizan dicho servicio (variaciones protegidas).

Composite: Para explicar el patrón Composite, seguimos con el ejemplo anterior, donde una venta, a través de un método polimorfico en el objeto Pago, podía justamente "pagar" el monto total de la venta. La pregunta es: que pasaría si un cliente decidiera pagar la mitad del valor de la venta con efectivo, y la otra mitad con tarjeta de crédito? Para solucionar este problema aparece el patrón "composite", que consiste en una colección de "estrategias".
En el caso del ejemplo anterior, un "composite" es un objeto que contiene una colección de "Pagos" (mas bien de métodos de pago), pero que implementa la misma interfaz que una sola estrategia o medio de pago. Esto quiere decir, que la venta, en realidad no es consciente si está tratando con un objeto combinado (un composite) o un objeto simple (una estrategia). Esto permite que, por ejemplo una sola venta pueda ser pagada con una forma de pago, a través del mensaje concretar() (enviado a un objeto "estrategia") o a través de varias formas de pago (a través del mensaje concretar() del objeto composite), sin que la venta tenga idea de como se implementa el método que responde dicho mensaje. En síntesis, un composite es una colección de objetos estrategia que implementa la misma interfaz que ellos, permitiendo enviar el mismo mensaje a un solo objeto, o a una colección de ellos.


Fachada: está muy relacionado con el patrón "Adaptador". La idea básica de este patrón es ocultar un subsistema detrás de un objeto, de tal manera, que pueda ocultarse la complejidad del subsistema.
"...Este patrón se utiliza cuando se requiere una interfaz común para un conjunto de implementaciones o interfaces dispares..." (UML y Patrones).
Cuando necesitamos acoplar un subsistema (o varios) a nuestra aplicación, podría NO ser deseable tener muchos puntos de acoplamiento (justamente para mantener un bajo acoplamiento). Para ello, se desarrolla una clase que funcione de intermediaria o de "fachada" para el/los subsistema/s en cuestión. De esta manera, podemos conectar la fachada a un único punto (o varios) en nuestra aplicación. Pero entonces, cual es la diferencia? La gran diferencia entre usar una fachada y conectar directamente un subsistema es que usando una fachada logramos variaciones protegidas. Si tenemos la fachada, conectada a varios puntos de nuestra aplicación, y el subsistema necesita ser modificado, podríamos ajustar las modificaciones solo en la fachada para incorporar los cambios introducidos en el subsitema, dejando la interfaz que implementa intacta, de tal manera que no es necesario modificar nuestra aplicación.

Existen otros (muchos) patrones de diseño interesantes y dignos de ser estudiados, pero los dejaremos para artículos siguientes. Por lo pronto, a aplicar lo aprendido!

Espero que les haya sido de mucha ayuda.

Comentarios:

Nombre:
Comentario: