Diseño de software

Strategy vs State: misma estructura, ¿cuál es la diferencia?

El patrón Strategy selecciona el algoritmo desde fuera, mientras que el patrón State deja que el estado actual impulse las transiciones internas. Ambos patrones de comportamiento comparten una estructura de clases, pero se distinguen por su intención y por quién controla los cambios.

4 min de lectura
Imagen de portada de Strategy vs State: misma estructura, ¿cuál es la diferencia?

Al estudiar patrones de diseño, hay un punto en el que casi inevitablemente nos atascamos.

Son los patrones Strategy y State.

Si colocas lado a lado los diagramas UML (Unified Modeling Language, lenguaje unificado de modelado), parecen prácticamente copiados y pegados. Hay una interfaz, varias implementaciones y un contexto que las contiene.

Es normal pensar: «¿No son simplemente nombres distintos?»

Empecemos por la conclusión. Lo que diferencia ambos patrones no es la estructura, sino la intención. Strategy cambia el algoritmo desde fuera; State hace que el estado avance por sí mismo al siguiente estado desde dentro.

Si te quedas con esta frase mientras lees, no volverás a confundirlos.

La implementación que elimina las condiciones reales mediante objetos de estado continúa paso a paso en Refactorización del patrón State en Swift.

¿Por qué sus estructuras son tan iguales?

Ambos son patrones de comportamiento del libro de patrones de diseño de GoF (Gang of Four).

Ambos usan los mismos elementos: una interfaz común, varias clases que la implementan y un contexto que las contiene.

Por eso resulta realmente difícil distinguirlos solo por el código.

Así se ve el patrón Strategy en código.

protocol PaymentStrategy {
    func pay(_ amount: Int)
}

struct CardPayment: PaymentStrategy {
    func pay(_ amount: Int) { print("Pago de  \(amount) won con tarjeta") }
}

struct KakaoPay: PaymentStrategy {
    func pay(_ amount: Int) { print("Pago de  \(amount) won con Kakao Pay") }
}

final class Checkout {
    var strategy: PaymentStrategy
    init(strategy: PaymentStrategy) { self.strategy = strategy }
    func pay(_ amount: Int) { strategy.pay(amount) }
}

let checkout = Checkout(strategy: CardPayment())
checkout.pay(10000)
checkout.strategy = KakaoPay()  // Se cambia desde fuera
checkout.pay(5000)
// Salida:
// Pago de  10000 won con tarjeta
// Pago de  5000 won con Kakao Pay

Lo importante aquí es quién cambia la strategy: el código cliente externo.

Quien cambió el método de pago de tarjeta a Kakao Pay fue el desarrollador, es decir, alguien externo.

La propia Strategy no sabe en absoluto qué viene después. Tampoco le importa.


Entonces, ¿qué diferencia al patrón State?

En el patrón State, los propios estados deciden las transiciones.

Piensa en un semáforo. La luz roja sabe que después viene la verde, y la verde sabe que después viene la amarilla.

Es decir, cada estado contiene la regla para pasar al siguiente.

El flujo en el que cada estado avanza por sí mismo: esa es la esencia de State
El flujo en el que cada estado avanza por sí mismo: esa es la esencia de State
protocol TrafficState {
    func next(_ light: TrafficLight)
}

final class Red: TrafficState {
    func next(_ light: TrafficLight) {
        print("Rojo → verde")
        light.state = Green()  // El estado especifica por sí mismo el siguiente
    }
}

final class Green: TrafficState {
    func next(_ light: TrafficLight) {
        print("Verde → amarillo")
        light.state = Yellow()
    }
}

final class Yellow: TrafficState {
    func next(_ light: TrafficLight) {
        print("Amarillo → rojo")
        light.state = Red()
    }
}

final class TrafficLight {
    var state: TrafficState = Red()
    func change() { state.next(self) }
}

let light = TrafficLight()
light.change()
light.change()
light.change()
// Salida:
// Rojo → verde
// Verde → amarillo
// Amarillo → rojo

¿Se ve la diferencia?

En Strategy, lo cambiamos directamente desde fuera, como en checkout.strategy = KakaoPay().

En State, light.state = Green() lo realiza la propia clase de estado. El cliente solo llama a change().

Ese es precisamente el punto clave.

Strategy se cambia desde fuera; State avanza por sí mismo desde dentro.


La diferencia decisiva, resumida en tres puntos

Explicarlo solo con palabras puede volver a confundir, así que lo resumimos en una tabla.

Categoría Patrón Strategy Patrón State
Intención Sustituir el algoritmo Cambiar el comportamiento según el estado
Quién realiza la transición Cliente externo El propio objeto de estado
Relación entre objetos No se conocen (independientes) Se conocen y se referencian
Ciclo de vida Normalmente se mantiene tras elegirlo Cambia continuamente durante la ejecución

Recuerda especialmente la segunda y la tercera fila.

Las strategies no conocen la existencia de las demás. Un pago con tarjeta no necesita conocer Kakao Pay.

En cambio, los estados deben conocerse entre sí. La luz roja crea y entrega directamente el objeto de luz verde.

Saber si «se conocen o no» es la pista más clara para distinguir ambos patrones en el código.

Al poner los dos códigos lado a lado, se ve quién cambia qué
Al poner los dos códigos lado a lado, se ve quién cambia qué

¿Cuándo conviene usarlos y cuándo evitarlos?

Estos son mis criterios para decidirlo en la práctica.

Situación Decisión
Cuando solo hay varias formas de hacer lo mismo (ordenación, pagos, compresión) Patrón Strategy
Cuando un objeto se comporta de forma distinta según la situación y esta cambia Patrón State
Cuando las reglas de transición forman un bloque complejo de if-else Resolver con State
Cuando es tan sencillo como pasar una sola función Ambos son excesivos; usa un closure

También hay que tener en cuenta lo siguiente.

Si solo hay 2 o 3 estados y las transiciones son simples, a menudo basta con enum y switch sin introducir un patrón.

Los patrones son herramientas para controlar la complejidad, no adornos para dar formalidad al código sencillo.

En una entrevista pueden preguntarlo así

P. Los patrones Strategy y State tienen la misma estructura. ¿Cómo se distinguen?

La estructura es casi igual, pero la intención es distinta. Strategy busca sustituir un algoritmo desde fuera, mientras que State busca cambiar el comportamiento según el estado interno. La diferencia decisiva es quién realiza la transición: el cliente en Strategy y el propio objeto de estado en State.

P. En State, los estados se referencian entre sí. ¿No es un problema?

Es cierto que aparece acoplamiento entre estados. Para reducirlo, puedes sacar la lógica de transición de los estados y llevarla al contexto o a una tabla de transiciones independiente. Si aumentan los estados y las transiciones se entrelazan, otra opción es usar una biblioteca de máquinas de estados.


No te intimides aunque los diagramas parezcan idénticos. Pregunta simplemente «¿Quién realiza la transición?» y la respuesta aparecerá enseguida.

Si se cambia desde fuera, es Strategy; si avanza por sí mismo desde dentro, es State. Con recordar esta frase, el artículo de hoy habrá cumplido su objetivo. Volveré con otro patrón que suele confundirse.

Lecturas relacionadas