Menu
Coddy logo textTech

Patrón State

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy. Lección 100 de 104.

El patrón State permite que un objeto cambie su comportamiento cuando cambia su estado interno, haciendo que parezca que el objeto cambió de clase. En lugar de usar instrucciones condicionales complejas para gestionar diferentes estados, encapsulas cada estado como una clase independiente.

El patrón consta de un Contexto que mantiene una referencia al estado actual, una interfaz State que define el comportamiento específico de cada estado y Estados concretos que implementan el comportamiento de cada estado:

#include <iostream>
#include <memory>

class Document;  // Declaración anticipada

// Interfaz de estado
class DocumentState {
public:
    virtual void publish(Document& doc) = 0;
    virtual std::string getName() const = 0;
    virtual ~DocumentState() = default;
};

// Contexto
class Document {
    std::unique_ptr<DocumentState> state;
public:
    Document();
    void setState(std::unique_ptr<DocumentState> newState) {
        state = std::move(newState);
    }
    void publish() { state->publish(*this); }
    std::string getStateName() const { return state->getName(); }
};

// Estados concretos
class Draft : public DocumentState {
public:
    void publish(Document& doc) override;
    std::string getName() const override { return "Draft"; }
};

class Review : public DocumentState {
public:
    void publish(Document& doc) override;
    std::string getName() const override { return "Review"; }
};

class Published : public DocumentState {
public:
    void publish(Document& doc) override {
        std::cout << "Already published\n";
    }
    std::string getName() const override { return "Published"; }
};

void Draft::publish(Document& doc) {
    std::cout << "Moving to review\n";
    doc.setState(std::make_unique<Review>());
}

void Review::publish(Document& doc) {
    std::cout << "Publishing document\n";
    doc.setState(std::make_unique<Published>());
}

Document::Document() : state(std::make_unique<Draft>()) {}

Cada estado gestiona la acción publish() de forma diferente y es responsable de pasar al estado siguiente. El Document no necesita conocer la lógica de transición: simplemente delega en el estado actual. Esto elimina las grandes instrucciones switch y facilita añadir nuevos estados.

Usa State cuando el comportamiento de un objeto dependa en gran medida de su estado y tengas muchas instrucciones condicionales que cambien según el estado del objeto.

challenge icon

Desafío

Fácil

Construyamos un Controlador de semáforo utilizando el patrón State. Crearás un sistema en el que un semáforo pasa por diferentes estados (Red, Yellow, Green), y cada estado determina qué ocurre cuando cambia el semáforo y qué mensaje se muestra. Este es un ejemplo clásico del patrón State: el comportamiento del semáforo depende por completo de su estado actual.

Organizarás tu código en tres archivos:

  • TrafficLightState.h: Define la interfaz del estado y todas las clases de estado concretas.

    Crea una clase abstracta TrafficLightState con:

    • Un método virtual puro change(TrafficLight& light) que gestiona la transición al estado siguiente
    • Un método virtual puro getColor() que devuelve el color actual como una cadena
    • Un método virtual puro getAction() que devuelve lo que deben hacer los conductores (por ejemplo, "Stop", "Caution", "Go")
    • Un destructor virtual

    Implementa tres estados concretos:

    • RedState: el color es "Red", la acción es "Stop" y cambia a Green
    • YellowState: el color es "Yellow", la acción es "Caution" y cambia a Red
    • GreenState: el color es "Green", la acción es "Go" y cambia a Yellow

    Necesitarás una declaración anticipada de TrafficLight, ya que los estados hacen referencia a ella.

  • TrafficLight.h: Crea la clase de contexto que mantiene el estado actual.

    Tu clase TrafficLight debe contener un std::unique_ptr<TrafficLightState> e iniciar en el estado Red de forma predeterminada. Implementa:

    • setState(std::unique_ptr<TrafficLightState> newState): cambia el estado actual
    • change(): delega en el método change del estado actual
    • display(): imprime el estado del semáforo con el formato: [Color]: [Action]
  • main.cpp: Demuestra el ciclo del semáforo a través de los estados.

    Lee una entrada: el número de cambios de estado que se deben realizar (un entero).

    Crea un TrafficLight y muestra su estado inicial. Después, realiza el número especificado de cambios y muestra el estado después de cada cambio.

Por ejemplo, con la entrada 3:

Red: Stop
Green: Go
Yellow: Caution
Red: Stop

Con la entrada 6:

Red: Stop
Green: Go
Yellow: Caution
Red: Stop
Green: Go
Yellow: Caution
Red: Stop

Observa cómo el semáforo recorre sus estados siguiendo un patrón predecible: Red → Green → Yellow → Red. Cada estado sabe qué estado viene después y gestiona su propia transición. La clase TrafficLight no necesita ninguna lógica condicional para determinar qué ocurre. Simplemente delega en el estado en el que se encuentra actualmente.

Pruébalo tú mismo

#include <iostream>
#include "TrafficLight.h"

using namespace std;

int main() {
    // Lee el número de cambios de estado
    int numChanges;
    cin >> numChanges;
    
    // TODO: Crea un objeto TrafficLight
    
    // TODO: Muestra el estado inicial
    
    // TODO: Realiza el número especificado de cambios
    // Después de cada cambio, muestra el estado actual
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C++ online