Strategy Pattern (Patrón Estrategia)

strategy

Imagina que eres el director técnico de un equipo de fútbol, y tienes un juego muy importante el próximo domingo, ¿cómo plantearías el juego?.

Como eres un buen director técnico, tienes que prever los posibles escenarios y tener una estrategia preparada para cada contexto.

De esa manera la formación y/o comportamiento de tus jugadores deberían cambiar dependiendo de los diversos factores que se presenten en el desarrollo juego, tales como: cuando atacas, cuando defiendes, expulsan a un jugador, vas ganando, vas perdiendo, juegan de visita, juegan de local, el rival es débil, el rival es fuerte, etc.

Strategy

Nuestra planificación sería de esta manera:

Con esto en mente veamos la parte técnica.

Definición

Este patrón define un conjunto de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Permite que el algoritmo pueda variar independientemente de los clientes que lo utilicen.

Esto quiere decir que nuestros objetos deben estar preparados para afrontar diversos contextos sin cambiar las interacciones de estos con el cliente.

Recuerda: Un algoritmo encapsulado es una estrategia

Modelo UML

strategy-uml

Participantes:

Las clases y objetos que participan en este modelo son:

  • Strategy
    • Declara una interfaz común para todos los algoritmos compatibles. El Contex utiliza esta interfaz para llamar al algoritmo definido por un ConcreteStrategy
  • ConcreteStrategy
    • Implementa el algoritmo utilizando la interfaz de Strategy
  • Context
    • Está configurado con un objeto ConcreteStrategy
    • Mantiene una referencia a un objeto de Strategy
    • Puede definir una interfaz que le permite acceder a sus datos Strategy.

Strategy Pattern en Acción

Strategy en acción

Notas

El patrón Strategy (estrategia) es una alternativa a la herencia, si estás pensando usar la herencia para poder agregar nuevos comportamientos a tus objetos, sería conveniente usar este patrón

Si dentro de tu clase haces uso intensivo de las condicionales if, else, swicth, case, eso quiere decir que tu clase tiene asignado muchos comportamientos y/o responsabilidades, lo cual suele ser un indicador de la necesidad aplicar el patrón Strategy (estrategia), para poder encapsular estos comportamientos y delegarlos a otra clase u objeto.

show

Veamos como se traduce la definición de este patrón a un código PHP

Context

Definimos nuestra clase Context, donde se pasarán las estrategias

namespace Behavioral\Strategy\Difinition;

class Context
{

  private $strategy;

  public function __construct($strategy)
  {
    $this->strategy = $strategy;
  }

  public function contextInterface()
  {
    $this->algorithmInterface();
  }

}

Strategy

Defendimos una interface StratageyInterface del cual se implementaran las demás estrategias

// StratageyInterface.php

namespace Behavioral\Strategy\Difinition;

interface StratageyInterface
{
   public function algorithmInterface();
}

ConcreteStrategy

Definimos una estrategia concreta llamada ConcreteStrategyA que encapsula nuestro algoritmo de comportamiento

//ConcreteStrategyA

namespace Behavioral\Strategy\Difinition;

use Behavioral\Strategy\Difinition\StratageyInterface;

class ConcreteStrategyA implements StratageyInterface
{

  public function algorithmInterface()
  {
    echo "Called ConcreteStrategyA->algorithmInterface()";
  }

}

Definimos otra estrategia concreta llamada ConcreteStrategyB que encapsula otro algoritmo de comportamiento

namespace Behavioral\Strategy\Difinition;

use Behavioral\Strategy\Difinition\StratageyInterface;

class ConcreteStrategyB implements StratageyInterface
{

  public function algorithmInterface()
  {
    echo "Called ConcreteStrategyB->algorithmInterface()";
  }

}

Main

Este seria la manera como invocaríamos a nuestro código

use Behavioral\Strategy\Difinition\Context;
use Behavioral\Strategy\Difinition\ConcreteStrategyA;
use Behavioral\Strategy\Difinition\ConcreteStrategyB;

$contextA = new Context(new ConcreteStrategyA());
$contextA->contextInterface();
//Show
//Called ConcreteStrategyA->algorithmInterface()

$contextB = new Context(new ConcreteStrategyB());
$contextB->contextInterface();
//Show
//Called ConcreteStrategyB->algorithmInterface()

Ejemplos del Mundo Real

Veamos la implementación de de una pequeña tienda virtual
Strategy Patern en acción con PHP

Conclusiones

Al usar este patrón estaremos cumpliendo 2 principios de SOLID que son: el principio de Responsabilidad única y el principio de Abierto y Cerrado, lo cual nos ayudará mucho cuando deseamos extender y/o añadir nuevas funcionalidades a nuestras clases sin mayores dolores de cabeza

benjamin
Me llamo Benjamín Gonzales B, soy desarrollador de software con más de 15 años de experiencia, socio funduador de la empresa GNBIT. Me apasiona todo lo relacionado a las nuevas tecnologías, me gusta investigar , leer y aprender cada día algo nuevo. Desarrollo en PHP7+, JAVA, C#, JavaScript, entre otros y actualmente  estoy experimentando con lenguajes funcionales como: Erlang, Clojure y Scala 

1 Comment

Leave a Comment

Su dirección de correo no se hará público. Los campos requeridos están marcados *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.