Programación Avanzada

Patrones de diseño

Concepto de patrón de diseño

Introducción

En el capítulo de introducción a los patrones de diseño, vimos que los patrones de diseño son soluciones estándar a problemas recurrentes en programación.

Este capítulo orientará el uso de patrones de diseño: como identificarlos y las recomendaciones de uso.

También veremos que los patrones de diseño se agrupan en familias, y agruparemos algunos patrones dentro de su familia correspondiente.

Bibliografía

Contenidos

  1. ¿Qué es un patrón de diseño?
  2. Familias de patrones de diseño.
  3. Como identificar problemas solubles con un patrón.
  4. Recomendaciones de uso.

¿Qué es un patrón de diseño?

Un patrón de diseño es una solución bien conocida a un problema recurrente en un contexto determinado.

En el caso de la POO, la solución al problema se explicita como un conjunto de clases, interfaces y sus relaciones.

¿Qué es un patrón de diseño?

Los patrones de diseño, además de proporcionar soluciones a problemas, nos proporcionan, como programadores, un lenguaje común.

Por ejemplo, si un compañero me dice que tiene un problema con su código porque necesita modificar el comportamiento de algunas de sus clase en tiempo de ejecución, y yo conozco la solución, le puedo decir que eche un vistazo al patrón Strategy.

¿Qué es un patrón de diseño?

La descripción de un patrón de diseño se hace a través de cuatro elementos fundamentales:

  1. Su nombre: intenta resumir en pocas palabras la idea del problema que pretende resolver y su solución.
  2. Problema que intenta resolver: expone el problema dentro del contexto en el que se presenta.
  3. La solución: las clases, interfaces y las relaciones entre ellos que forman la solución.
  4. Las consecuencias: las ventajas e inconvenientes de aplicar la solución.

Una implementación en algún lenguaje de programación popular también es de ayuda.

¿Qué es un patrón de diseño?

Veamos el caso del patrón de diseño Strategy.

  1. Nombre: Strategy (Estrategia)
  2. Problema que intenta resolver: No tenemos una solución única para un problema concreto. Por ejemplo, conocemos varios algoritmos de ordenación pero no queremos restringirnos sólo a uno de ellos, es más, queremos poder cambiar entre ellos de forma dinámica (en tiempo de ejecución).

¿Qué es un patrón de diseño?

3. La solución

Define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Permite que un algoritmo varíe independientemente de los clientes que lo usan.

¿Qué es un patrón de diseño?

4. Las consecuencias:

Ventajas:

  1. Permite manipular de modo transparente familias de algoritmos.
  2. Es una alternativa a la herencia.
  3. Evitan las sentencias switch.

Desventajas

  1. La decisión del algoritmo a elegir quizás deba basarse en su implementación.
  2. Mayor número de objetos en la solución.

Familias de patrones de diseño

Existe una gran cantidad de patrones de diseño. Algunos de ellos como Strategy son muy recurrentes, otros no lo son tanto.

Para poder trabajar con ellos resulta interesante agruparlos según su propósito, de ahí nacen las familias de patrones de diseño.

Existen tres grandes familias de patrones de diseño: De Creación, Estructurales y De Comportamiento.

Familias de patrones de diseño

Familia de patrones de diseño de Creación.

Una paradoja: No uses el operador new para crear instancias de una clase, ¿cómo las obtengo entonces ?

Con algún patrón de la familia de Creación.

Familias de patrones de diseño

Familia de patrones de diseño de Creación.

Un ejemplo: Supón que estás desarrollando una aplicación para la gestión de clínicas dentales. Los datos de los clientes están en una base de datos, ¿en cual?, ni idea, puede ser MySQL, Oracle, PostgreSQL, Access, etcétera.

Con independencia del gestor, de algún modo obtendré acceso a la base de datos y podré hacer consultas SQL.

Afortunadamente, Java resuelve este problema con la biblioteca jdbc. Independientemente del gestor, yo le pido a un Factory que me devuelva una instancia para conectarme a la base de datos.

¿Y si cambia el gestor?

Me da igual, quien se tiene que preocupar es Factory, yo sólo soy su cliente.

Familias de patrones de diseño

Familia de patrones de diseño Estructurales.

Permiten componer nuevos objetos a partir de objetos ya existentes. Es más flexible que la herencia y la agregación, ya que puede actuar dinámicamente.

Hasta ahora, hemos creado nuevas clases a partir de otras existentes utilizando la herencia y la composición.

Los patrones de diseño Estructurales nos permiten construir clases a partir de otras de un modo más flexible.

Familias de patrones de diseño

Familia de patrones de diseño Estructurales.

Supón, por ejemplo, que estás desarrollando un interfaz de usuario. Creas objetos que representan ventanas, botones, listas, árboles desplegables etcétera.

Ahora tienes la necesidad de añadir barras de desplazamiento a tus elementos gráficos, para poderlas añadir a una ventana, a una lista, etcétera.

Familias de patrones de diseño

Familia de patrones de diseño Estructurales.

Se te pueden ocurrir dos soluciones:

  1. Utilizar la herencia y extender tus clases añadiendo a las nuevas clases hijas la nueva funcionalidad que necesitas.
  2. Crear una nueva clase que posea como atributos la clase Ventana y la clase BarraDeDesplazamiento

Las dos soluciones son válidas, pero poco flexibles.

Familias de patrones de diseño

Familia de patrones de diseño Estructurales.

Si eliges la primera solución: ¿Qué ocurre si quieres tener una ventana con barras de desplazamiento y un título?

¿Y si quieres barras de desplazamiento, un título y bordes circulares?

¿Y si quieres barras de desplazamiento, bordes circulares pero no título?

Uf!, parece que tengo un explosión de clases.

Familias de patrones de diseño

Familia de patrones de diseño Estructurales.

Si optas por la segunda solución, y creas un atributo en la clase Ventana por cada nueva propiedad que quieras añadir:

  1. Si la Ventana sólo tiene barra de desplazamiento, el resto de atributos no estarán iniciados.
  2. Cada vez que quieras añadir nuevo comportamiento tendrás que modificar (abrir) la clase y hacer los cambios.

Como veremos, en este caso el patrón Decorator nos puede ayudar.

Familias de patrones de diseño

Familia de patrones de diseño de Comportamiento.

En esta familia encontramos patrones que nos permiten cambiar dinámicamente el comportamiento de los objetos o las relaciones entre ellos.

El patrón Strategy pertenece a esta familia. Nos permite cambiar dinámicamente, es decir, en tiempo de ejecución, la implementación de un algoritmo.

Familias de patrones de diseño

CreaciónEstructuralesComportamiento
ClaseFactory MethodAdapterInterpreter
Template method
Objeto
Abstract FactoryAdapterChain of Responsibility
BuilderBridgeCommand
PrototypeCompositeIterator
SingletonDecoratorMediator
FacadeMemento
FlyweightObserver
ProxyState
Strategy
Visitor
Erich Gamma et al.
Patrones de diseño.

Cómo identificar problemas solubles con un patrón

Evitando al máximo el acoplamiento:

  1. Cada vez que necesito una clase recurro al método new.
  2. Estoy programando para un hardware o un API particular.
  3. Mi implementación depende de la implementación de otras clases y no sólo de su interfaz.
  4. Quiero utilizar varios algoritmos sin que afecte al diseño.
  5. El único modo que he utilizado para añadir funcionalidad a mis clases ha sido la herencia.
  6. Una clase de un API no me da la funcionalidad que necesito o su interfaz pública no es la que necesito.

Recomendaciones de uso

No abuses de los patrones de diseño: no intentes usar un patrón de diseño sólo porque lo conoces, te puede complicar más que ayudar.

Los patrones de diseño son una plantilla de soluciones, los puedes usar adaptándolos a tu problema particular. Pero respeta siempre el concepto sobre el que descansa, si tienes que modificar demasiadas cosas de un patrón para que se adapte a tu problema, quizás sea mejor no utilizarlo.

Resumen

Los patrones de diseño son soluciones muy probadas a problemas recurrentes en POO.

Existe una gran cantidad de patrones de diseño. Para facilitar su uso se agrupan en familias.

Cada familia es un ámbito genérico a la solución. Las principales familias son: De Creación, Estructural y De Comportamiento.

Cuantos más patrones conozcas, antes resolverás los problemas de diseño que pueden aparecer en tu código.

No caigas en la tiranía de su uso si no te resuelve ningún problema de diseño. No utilices un patrón sólo porque lo conoces.