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 su estado interno cambia, haciendo que parezca como si el objeto hubiera cambiado su clase. En lugar de utilizar sentencias condicionales complejas para manejar diferentes estados, se encapsula cada estado como una clase separada.

El patrón consiste en un Context que mantiene una referencia al estado actual, una interfaz State que define el comportamiento específico del estado y Concrete States que implementan el comportamiento para cada estado:

#include <iostream>
#include <memory>

class Document;  // Declaración adelantada

// 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 maneja la acción publish() de manera diferente y es responsable de la transición al siguiente estado. El Document no necesita conocer la lógica de transición; simplemente delega en el estado actual. Esto elimina las sentencias switch grandes y hace que añadir nuevos estados sea sencillo.

Usa State cuando el comportamiento de un objeto depende en gran medida de su estado y tienes muchas sentencias condicionales que cambian según el estado del objeto.

challenge icon

Desafío

Fácil

Vamos a construir un Controlador de Semáforo utilizando el patrón State. Crearás un sistema donde un semáforo alterna entre diferentes estados (Red, Yellow, Green), y cada estado determina qué sucede cuando la luz cambia y qué mensaje se muestra. Este es un ejemplo clásico del patrón State: el comportamiento del semáforo depende enteramente de su estado actual.

Organizarás tu código en tres archivos:

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

    Crea una clase abstracta TrafficLightState con:

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

    Implementa tres estados concretos:

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

    Necesitarás una declaración anticipada (forward declaration) para 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 por defecto. Implementa:

    • setState(std::unique_ptr<TrafficLightState> newState) — cambia el estado actual
    • change() — delega al método change del estado actual
    • display() — imprime el estado del semáforo en 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 a realizar (entero).

    Crea un TrafficLight y muestra su estado inicial. Luego realiza el número especificado de cambios, mostrando 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 alterna entre sus estados en un patrón predecible: Red → Green → Yellow → Red. Cada estado sabe qué estado sigue y maneja su propia transición. La clase TrafficLight no necesita ninguna lógica condicional para determinar qué sucede; simplemente delega a cualquier estado en el que se encuentre actualmente.

Pruébalo tú mismo

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

using namespace std;

int main() {
    // Leer el número de cambios de estado
    int numChanges;
    cin >> numChanges;
    
    // TODO: Crear un objeto TrafficLight
    
    // TODO: Mostrar el estado inicial
    
    // TODO: Realizar el número especificado de cambios
    // Después de cada cambio, mostrar 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