Menu
Coddy logo textTech

Padrão State

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 100 de 104.

O padrão State permite que um objeto altere seu comportamento quando seu estado interno muda, fazendo parecer que o objeto mudou de classe. Em vez de usar instruções condicionais complexas para lidar com diferentes estados, você encapsula cada estado como uma classe separada.

O padrão consiste em um Contexto que mantém uma referência ao estado atual, uma interface de Estado que define o comportamento específico de cada estado e Estados Concretos que implementam o comportamento de cada estado:

#include <iostream>
#include <memory>

class Document;  // Declaração antecipada

// Interface 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 lida com a ação publish() de forma diferente e é responsável por fazer a transição para o próximo estado. O Document não precisa conhecer a lógica de transição — ele simplesmente delega ao estado atual. Isso elimina grandes instruções switch e torna simples adicionar novos estados.

Use State quando o comportamento de um objeto depende muito do seu estado e você tem muitas instruções condicionais que alternam com base no estado do objeto.

challenge icon

Desafio

Fácil

Vamos criar um Controlador de Semáforo usando o padrão State. Você criará um sistema no qual um semáforo alterna entre diferentes estados (Red, Yellow, Green), com cada estado determinando o que acontece quando o sinal muda e qual mensagem é exibida. Este é um exemplo clássico do padrão State: o comportamento do semáforo depende inteiramente do seu estado atual.

Você organizará seu código em três arquivos:

  • TrafficLightState.h: Defina a interface do estado e todas as classes de estado concretas.

    Crie uma classe abstrata TrafficLightState com:

    • Um método virtual puro change(TrafficLight& light) que gerencia a transição para o próximo estado
    • Um método virtual puro getColor() que retorna a cor atual como uma string
    • Um método virtual puro getAction() que retorna o que os motoristas devem fazer (por exemplo, "Stop", "Caution", "Go")
    • Um destrutor virtual

    Implemente três estados concretos:

    • RedState: a cor é "Red", a ação é "Stop" e muda para Green
    • YellowState: a cor é "Yellow", a ação é "Caution" e muda para Red
    • GreenState: a cor é "Green", a ação é "Go" e muda para Yellow

    Você precisará de uma declaração antecipada para TrafficLight, pois os estados fazem referência a ela.

  • TrafficLight.h: Crie a classe de contexto que mantém o estado atual.

    Sua classe TrafficLight deve conter um std::unique_ptr<TrafficLightState> e começar no estado Red por padrão. Implemente:

    • setState(std::unique_ptr<TrafficLightState> newState): altera o estado atual
    • change(): delega para o método change do estado atual
    • display(): imprime o status do semáforo no formato: [Color]: [Action]
  • main.cpp: Demonstre o semáforo alternando entre os estados.

    Leia uma entrada: o número de mudanças de estado a realizar (inteiro).

    Crie um TrafficLight e exiba seu estado inicial. Em seguida, realize o número especificado de mudanças, exibindo o estado após cada mudança.

Por exemplo, com a entrada 3:

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

Com a entrada 6:

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

Observe como o semáforo alterna entre seus estados em um padrão previsível: Red → Green → Yellow → Red. Cada estado sabe qual estado vem em seguida e gerencia sua própria transição. A classe TrafficLight não precisa de nenhuma lógica condicional para determinar o que acontece. Ela simplesmente delega para o estado em que se encontra atualmente.

Experimente você mesmo

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

using namespace std;

int main() {
    // Lê o número de mudanças de estado
    int numChanges;
    cin >> numChanges;
    
    // TODO: Crie um objeto TrafficLight
    
    // TODO: Exiba o estado inicial
    
    // TODO: Realize o número especificado de mudanças
    // Após cada mudança, exiba o estado atual
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C++ online