Patrones de diseño

Los patrones de diseño fueron introducidos en el libro de Gamma, Helm, Johnson y Vlissides: Design Patterns: Elements of Reusable OBject-Oriented Software, publicado en 1994. Se considera uno de los libros fundamentales para el moderno desarrollo de software.

Los patrones describen problemas de diseño y soluciones adecuadas para los mismos. No se trata de recetas que se puedan copiar y pegar. Más bien se trata de directrices para identificar el tipo de problema que se pretende solucionar y un modelo de clases que resuelve ese problema de una manera probada. Es tarea de cada desarrollador llevar a cabo la implementación del patrón adecuada a su proyecto.

Estos patrones, a su vez, ayudan a componer un lenguaje que permite la comunicación entre programdores, incluso cuando no están utilizando los mismos lenguajes de programación, ya que los patrones son completamente independientes de los mismos.

Por lo general, los elementos del patrón son:

  • La situación o abanico de situaciones que se trata de afrontar.
  • El modelo de clases que resuelve el problema y los elemntos que intervienen: clases, interfaces, subclases, etc.

El patrón Fachada (Facade)

El patrón Fachada es un patrón de tipo estructural que persigue encapsular operaciones complejas o repetitivas en una interfaz simplificada. El patrón Fachada ayuda a lograr DRY y KISS.

Supongamos que queremos o tenemos que utilizar una librería de código, ya sea procedural u orientada a objetos, la cual resulta compleja de manejar o que requiere muchas instrucciones repetitivas y/o preparación de datos y otros objetos cada vez que queremos realizar alguna tarea. La solución sería construir una clase “fachada” con métodos que utilicen esa librería. Nuestra aplicación se relaciona con la Fachada y no tiene que saber nada acerca de la librería.

En cierto modo, el patrón Fachada es la base de otros patrones como el Adaptador o el Decorador pues, al igual que éstos, envuelve o encapsula un código para que sea accesible de un modo diferente y más conveniente para la aplicación.

Las diferencias serían:

  • La Fachada busca simplificar una interfaz compleja para hacerla manejable.
  • El Adaptador busca convertir la interfaz “externa” en una interfaz esperada por las clases cliente, que suele estar definida explícitamente, y persigue habilitar el polimorfismo.
  • El decorador añade funcionalidad a un objeto en tiempo de ejecución envolviéndolo, pero no busca cambiar la interfaz.

Un caso típico en PHP es el acceso a la base de datos, para lo que es habitual crear una clase que simplifique los pasos de configuración, conexión, petición de datos, etc. Otro ejemplo puede ser el uso de la librería gráfica GD.

Los elementos del patrón sería:

  • Fachada: la clase que encapsula. Utilza el Sistema encapsulado para realizar su tarea.
  • Sistema encapsulado: una librería, una clase compleja, una colección de clases relacionadas, etc. No sabe nada de la fachada.
  • Usuarios: el código usuario de la Fachada y que quiere usar el sistema encapsulado. Conoce la interfaz de Fachada, y no sabe nada del sistema encapsulado.

Las Fachadas nos ayudan en varios aspectos:

  • Reducen la complejidad del código al delegar en un objeto especializado llamadas complejas al sistema encapsulado.
  • Mejoran la mantenibilidad al centralizar en un sólo lugar código que puede ser utilzado muchas veces.
  • Reduce la complejidad de las dependencias, al confinarlas a una clase, lo que, a su vez, permite cambiarlas fácilmente reescribiendo la fachada (que es la base del patrón Adaptador). Aunque la fachada está fuertemente acoplada al sistema encapsulado, pero de ese modo desacopla el resto de la aplicación.
  • Nos permite crear puntos de entrada entre capas o subsistemas.

El patrón repositorio

El patrón repositorio se utiliza en Diseño Dirigido por el Dominio para proporcionar persistencia en la capa del dominio sin acoplarla con una implementación concreta.

El patrón especificación (Specification)

El patrón especificación encapsula las reglas de negocio para seleccionar objetos.

Al usar el patrón repositorio podemos encontrarnos el problema de tener que crear métodos para hacer selecciones específicas de objetos. Cada vez que necsitamos una nueva selección con nuevos criterios tendríamos que crear un método nuevo que aplique los correspondientes criterios. El patrón especificación soluciona ese problema encapsulando las condiciones en un objeto sencillo con un único método isSatisfiedBy al que se le pasa un objeto del dominio y que devuelve un valor boolean.

Esto nos indica si los objetos individuales satisfacen la especificación por lo que el repositorio tendría que obtener antes todos los objetos almacenados y examinarlos uno por uno hasta encontrar todos los que la cumplen. Por supuesto, en muchos sistemas esta tarea consume excesivos recursos por lo que debemos encontrar un método más económico. Por ejemplo, un sistema que sea capaz de cargar una selección manejable de objetos y que aplique luego la especificación en ellos, o bien, una traducción de la especificación al lenguaje del almacenamiento concreto.

En este último caso, puede ser interesante que la Especificación contenga un método que devuelva las reglas de negocio de una manera que pueda ser usada por el repositorio para hacer la consulta al medio de almacenamiento. Por ejemplo, si es un repositorio basado en SQL, podríamos tener un método asSql() que simplemente nos devuelva la petición tal como la necesitaríamos para realizar la consulta en la base de datos. Esto difumina un poco las fronteras entre capas, pero simplifica el código del Repositorio y elimina la necesidad de un intermediario que traduzca la especificación. Pero, al fin y a la postre, el Repositorio mismo es un espacio de frontera y, en la práctica, la Especificación sigue perteneciendo al dominio.

Otro uso de la Especificación podría ser la validación. En efecto, isSatisfiedBy es un método de validación, ya que comprueba que el objeto que se le pasa cumple con ciertas condiciones.

La primera ventaja es que el Repositorio no necesita conocer tanto de la Entidad o del Agregado que maneja, sino que esta tarea queda en manos de las diferentes especificaciones.

Si necesitamos usar nuevos conjuntos de criterios no tendríamos más que crear una nueva Especificación y utilizarla.

http://culttt.com/2014/08/25/implementing-specification-pattern/

Es una manera de encapsular reglas de negocio para devolver un valor boolean. Nos permite crear clases que tengan una sola responsabilidad y que se puedan combinar con otros objetos del mismo tipo (especificaciones) para gestionar requisitos complejos.

La Especificación tiene un método público isSatisfiedBy que devuelve un boolean.

Este patrón funciona bien para validar objetos, pero no tanto para seleccionarlos.

En este caso habría que usar DoubleDispatch crear un método satisfyingElementsFrom en la especficación que se corresponda con un método de selección en el repositorio. El repositorio podría utilizar una petición para obtener un conjunto de datos próximo y usar la especificacion para filtrarlos.

http://stackoverflow.com/questions/33331007/implement-specification-pattern

Especificaciones compuestas

Nos permiten crear especificaciones complejas combinando otras más simples. Aquí hay una explicación clara:

http://marcaube.ca/2015/05/specifications/

Especificaciones compuestas