En programación de computadoras , el patrón de estrategia (también conocido como patrón de política ) es un patrón de diseño de software de comportamiento que permite seleccionar un algoritmo en tiempo de ejecución. En lugar de implementar un único algoritmo directamente, el código recibe instrucciones de tiempo de ejecución sobre cuál de una familia de algoritmos utilizar. [1]
La estrategia permite que el algoritmo varíe independientemente de los clientes que lo utilicen. [2] La estrategia es uno de los patrones incluidos en el influyente libro Design Patterns de Gamma et al. [3] que popularizó el concepto de utilizar patrones de diseño para describir cómo diseñar software orientado a objetos flexible y reutilizable. Aplazar la decisión sobre qué algoritmo utilizar hasta el tiempo de ejecución permite que el código de llamada sea más flexible y reutilizable.
Por ejemplo, una clase que realiza validación de datos entrantes puede usar el patrón de estrategia para seleccionar un algoritmo de validación dependiendo del tipo de datos, la fuente de los datos, la elección del usuario u otros factores discriminatorios. Estos factores no se conocen hasta el tiempo de ejecución y pueden requerir la realización de una validación radicalmente diferente. Los algoritmos de validación (estrategias), encapsulados por separado del objeto de validación, pueden ser utilizados por otros objetos de validación en diferentes áreas del sistema (o incluso en diferentes sistemas) sin duplicación de código .
Normalmente, el patrón de estrategia almacena una referencia al código en una estructura de datos y la recupera. Esto se puede lograr mediante mecanismos como el puntero de función nativa , la función de primera clase , clases o instancias de clase en lenguajes de programación orientados a objetos , o accediendo al almacenamiento interno de código de la implementación del lenguaje a través de la reflexión .
En el diagrama de clases UML anterior , la clase no implementa un algoritmo directamente. En cambio, se refiere a la interfaz para realizar un algoritmo ( ), lo que lo hace independiente de cómo se implementa un algoritmo. Las clases y implementan la interfaz, es decir, implementan (encapsulan) un algoritmo.
El diagrama de secuencia UML
muestra las interacciones en tiempo de ejecución: el objeto delega un algoritmo a diferentes objetos. Primero, llama a un objeto, que realiza el algoritmo y devuelve el resultado . A partir de entonces, cambia su estrategia y llama a un objeto, que realiza el algoritmo y devuelve el resultado .Context
Context
Strategy
strategy.algorithm()
Context
Strategy1
Strategy2
Strategy
Context
Strategy
Context
algorithm()
Strategy1
Context
Context
algorithm()
Strategy2
Context
[5]
Según el patrón estratégico, los comportamientos de una clase no deberían heredarse. En cambio, deberían encapsularse mediante interfaces. Esto es compatible con el principio abierto/cerrado (OCP), que propone que las clases deben estar abiertas a la extensión pero cerradas a la modificación.
Como ejemplo, consideremos una clase de automóvil. Dos posibles funcionalidades para el coche son frenar y acelerar . Dado que los comportamientos de aceleración y frenado cambian con frecuencia entre modelos, un enfoque común es implementar estos comportamientos en subclases. Este enfoque tiene importantes inconvenientes; Los comportamientos de aceleración y frenado deben declararse en cada modelo de automóvil nuevo. El trabajo de gestionar estos comportamientos aumenta enormemente a medida que aumenta el número de modelos y requiere que el código se duplique entre los modelos. Además, no es fácil determinar la naturaleza exacta del comportamiento de cada modelo sin investigar el código de cada uno.
El patrón de estrategia utiliza composición en lugar de herencia . En el patrón de estrategia, los comportamientos se definen como interfaces separadas y clases específicas que implementan estas interfaces. Esto permite un mejor desacoplamiento entre el comportamiento y la clase que utiliza el comportamiento. El comportamiento se puede cambiar sin romper las clases que lo usan, y las clases pueden cambiar entre comportamientos cambiando la implementación específica utilizada sin requerir ningún cambio significativo en el código. Los comportamientos también se pueden cambiar en tiempo de ejecución y en tiempo de diseño. Por ejemplo, el comportamiento de frenado de un objeto automóvil se puede cambiar de BrakeWithABS()
a Brake()
cambiando el brakeBehavior
miembro a:
BrakeBehavior = nuevo freno ();
/* Familia encapsulada de algoritmos * Interfaz y sus implementaciones */ public interface IBrakeBehavior { public void Brake (); } La clase pública BrakeWithABS implementa IBrakeBehavior { freno vacío público () { Sistema . afuera . println ( "Freno con ABS aplicado" ); } } El freno de clase pública implementa IBrakeBehavior { freno vacío público () { Sistema . afuera . println ( "Freno simple aplicado" ); } } /* Cliente que puede usar los algoritmos anteriores indistintamente */ public abstract class Car { private IBrakeBehavior BrakeBehavior ; coche público ( IBrakeBehavior BrakeBehavior ) { this . comportamientofreno = comportamientofreno ; } aplicar freno público vacío () { frenoBehavior . freno (); } public void setBrakeBehavior ( IBrakeBehavior tipo de freno ) { this . comportamientofreno = tipofreno ; } } /* El cliente 1 usa un algoritmo (Brake) en el constructor */ public class Sedan extends Car { public Sedan () { super ( new Brake ()); } } /* El cliente 2 usa otro algoritmo (BrakeWithABS) en el constructor */ public class SUV extends Car { public SUV () { super ( new BrakeWithABS ()); } } /* Usando el ejemplo de Auto */ public class CarExample { public static void main ( final String [] argumentos ) { Car sedanCar = new Sedan (); sedánCoche . aplicar freno (); // Esto invocará la clase "Freno" Coche suvCar = SUV nuevo (); todoterreno . aplicar freno (); // Esto invocará la clase "BrakeWithABS" // establece el comportamiento de los frenos dinámicamente suvCar . setBrakeBehavior ( nuevo freno () ); todoterreno . aplicar freno (); // Esto invocará la clase "Freno" } }
{{cite book}}
: Mantenimiento CS1: varios nombres: lista de autores ( enlace )