El patrón Strategy
Descripción
El patrón Strategy tiene como objetivo adaptar el comportamiento y los algoritmos de un objeto en función de una necesidad sin cambiar las interacciones de este objeto con los clientes.
Esta necesidad puede ponerse de relieve en base a aspectos tales como la presentación, la eficacia en tiempo de ejecución o en memoria, la elección de algoritmos, la representación interna, etc. Aunque evidentemente no se trata de una necesidad funcional de cara a los clientes del objeto pues las interacciones entre el objeto y sus clientes deben permanecer inmutables.
Ejemplo
En el sistema de venta online de vehículos, la clase VistaCatálogo dibuja la lista de vehículos destinados a la venta. Se utiliza un algoritmo de diseño gráfico para calcular la representación gráfica en función del navegador. Existen dos versiones de este algoritmo:
-
una primera versión que sólo muestra un vehículo por línea (un vehículo ocupa todo el ancho disponible) y que muestra toda la información posible así como cuatro fotografías;
-
una segunda versión que muestra tres vehículos por línea pero que muestra menos información y una única fotografía.
La interfaz de la clase VistaCatálogo no depende de la elección del algoritmo de representación gráfica. Esta elección no tiene impacto alguno en la relación de una vista de catálogo con sus clientes. Sólo se modifica la representación.
Una primera solución consiste en transformar la clase VistaCatálogo en una interfaz o en una clase abstracta y en incluir dos subclases de implementación diferentes según la elección del algoritmo. Esto presenta el inconveniente de complicar de manera inútil la jerarquía de las vistas del catálogo.
Otra posibilidad consiste en implementar ambos algoritmos en la clase VistaCatálogo y en apoyarse en instrucciones...
Estructura
1. Diagrama de clases
La figura 4-10.2 muestra la estructura genérica del patrón.
Figura 4-10.2 - Estructura del patrón Strategy
2. Participantes
Los participantes del patrón son los siguientes:
-
Estrategia (DibujaCatálogo) es la interfaz común a todos los algoritmos. Esta interfaz se utiliza en Entidad para invocar al algoritmo.
-
EstrategiaConcretaA y EstrategiaConcretaB (DibujaUnVehículoPorLínea y DibujaTresVehículosPorLínea) son las subclases concretas que implementan los distintos algoritmos.
-
Entidad es la clase que utiliza uno de los algoritmos de las clases que implementan la Estrategia. Por consiguiente, posee una referencia hacia una de estas clases. Por último, si fuera necesario, puede exponer sus datos internos a las clases de implementación.
3. Colaboraciones
La entidad y las instancias de las clases de implementación de la Estrategia interactúan para implementar los algoritmos. En el caso más sencillo, los datos que necesita el algoritmo se pasan como parámetro. Si fuera necesario, la clase Entidad introduciría los métodos necesarios para dar acceso a sus datos internos.
El cliente inicializa la entidad con una instancia de la clase de implementación de Estrategia. Él mismo selecciona esta clase y, por lo general, no la modifica a continuación. La entidad puede modificar a continuación esta elección....
Dominios de aplicación
El patrón se utiliza en los casos siguientes:
-
El comportamiento de una clase puede estar implementado mediante distintos algoritmos siendo alguno de ellos más eficaz en términos de ejecución o de consumo de memoria o incluso contienen mecanismos de decisión.
-
La implementación de la elección del algoritmo mediante instrucciones condicionales se vuelve demasiado compleja.
-
Un sistema posee numerosas clases idénticas salvo una parte correspondiente a su comportamiento.
En el último caso, el patrón Strategy permite reagrupar estas clases en una sola, lo que simplifica la interfaz para los clientes.
Ejemplo en C#
Nuestro ejemplo escrito en C# está basado en la visualización del catálogo de vehículos, simulado aquí simplemente mediante salidas por pantalla.
La interfaz DibujaCatalogo incluye el método dibuja que recibe como parámetro una lista de instancias de VistaVehiculo.
using System.Collections.Generic;
public interface DibujaCatalogo
{
void dibuja(IList<VistaVehiculo> contenido);
}
La clase DibujaUnVehiculoPorLinea implementa el método dibuja mostrando un vehículo por cada línea (imprime un salto de línea tras mostrar un vehículo).
using System;
using System.Collections.Generic;
public class DibujaUnVehiculoPorLinea : DibujaCatalogo
{
public void dibuja(IList<VistaVehiculo> contenido)
{
Console.WriteLine(
"Dibuja los vehículos mostrando un vehículo por línea");
foreach (VistaVehiculo vistaVehiculo in contenido)
{
vistaVehiculo.dibuja();
Console.WriteLine();
}
Console.WriteLine();
}
}
La clase DibujaTresVehiculosPorLinea implementa el método...