Continuamos con la serie de patrones de diseño. Hoy hablamos del patrón Estrategia.
Propósito
Definir una familia de algoritmos, encapsular cada uno y hacerlos intercambiables. Este patrón permite cambiar de algoritmo independientemente del cliente.
Motivación
Muchas veces tenemos un método con varias versiones. Por ejemplo un método para encriptar una cadena de texto. Existen muchos algoritmos para encriptar una cadena de texto y en función de ciertos aspectos debemos utilizar uno u otro. Si no utilizáramos ningún patrón esto se traduciría en un montón de ifs o en un switch en nuestro método. Para solucionar eso, lo que hacemos es definir clases para encapsular en cada una una versión del algoritmo de tal forma que el cliente llamaría a una de esas clases y parmanecería ajeno a si el método varía o no.
Aplicabilidad
El patrón Estrategia se usa cuando:
- Varias clases difieren en el comportamiento de una o dos responsabilidades.
- Es necesario implementar diversas variantes de un mismo algoritmo y seleccionar una variante concreta en tiempo de ejecución.
- Una clase define muchos comportamientos y eso se traduce en un montón de condicionales en sus métodos.
Estructura
La clase Strategy es una interfaz que es de la que tendrá conocimiento la clase cliente, que es la que tiene la necesidad de implementar varias versiones de un algoritmo por ejemplo. Cada versión del algoritmo será implementada por una clase que implementa a la interfaz Strategy. La clase cliente en este caso Context tendrá una referencia a la interfaz Strategy. Cada vez que necesite usar una versión del algoritmo lo que habrá que hacer es instanciar esa referencia con una de las clases que implementan la versión del algoritmo. De esa forma evitamos un gran número de condicionales.
Consecuencias
Los beneficios de este patrón son los siguientes:
- Familias de algoritmos relacionados: La jerarquía de clases define una familia de algoritmos o de comportamientos que se pueden reutilizar. La herencia puede ayudar a factorizar la funcionalidad común de los algoritmos.
- Una alternativa a las subclases: La herencia supone otra forma de soportar una variedad de algoritmos o comportamientos. Podríamos crear subclases de la clase Contexto para darle distintos comportamientos. Sin embargo esto mezclaría la implementación del algoritmo con la clase Contexto lo que haría que ésta fuera más difícil de entender, mantener y extender además de no poder cambiar el algoritmo en tiempo de ejecución. Estas ventajas si que nos las proporciona el encapsulamiento del algoritmo en subclases separadas de la interfaz Strategy.
- Elimina las estructuras condicionales: El patrón Estrategia ofrece una alternativa a las estructuras condicionales para seleccionar el comportamiento deseado. Cuando los diferentes comportamientos están agrupados en una sola clase es complicado no utilizar condicionales. Encapsular los comportamientos en clases separadas elimina esos condicionales. Si un código contiene muchos condicionales puede indicar que es necesario utilizar este patrón.
Por contra, las pegas de usar este patrón son las siguientes:
- Overhead de comunicación entre Context y Strategy: La interfaz Strategy es compartida por todas las clases concretas (las que implementan los algoritmos). Muchas veces esas clases no usarán toda la información que se les pasa a traves de la interfaz. Lo que significa que habra momentos en los que la clase Context crea e inicializa parámetros que no serán usados por lo que no sería necesario ese acoplamiento entre Context y Strategy.
- Incrementa el número de objetos: El patrón provoca que sea necesario crear más objetos. Si tuviésemos todos los posibles comportamientos en una sola clase no tendríamos que crear ningún objeto adicional. Esto es algo que pasa con muchos patrones. Sin embargo, el uso de memoria es menos importante que la complejidad por lo que siempre es más conveniente usar el patrón que no usarlo.
Usos conocidos
El método list de la clase File del paquete java.io utiliza este patrón.
El artículo Patrones de Diseño. Patrón Estrategia. apareció por primera vez en Instinto Binario.