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 60 de 70.

El patrón State es un patrón de comportamiento que permite que un objeto cambie su comportamiento cuando su estado interno cambia. En lugar de utilizar sentencias condicionales complejas para gestionar diferentes estados, se encapsula cada estado en su propia clase y se delega el comportamiento al objeto de estado actual.

El patrón consta de tres componentes: una interfaz de estado que define el comportamiento específico del estado, clases de estado concretas que implementan dicho comportamiento y una clase de contexto que mantiene una referencia al estado actual:

public interface IDocumentState
{
    void Publish(Document doc);
}

public class DraftState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Moving to moderation");
        doc.SetState(new ModerationState());
    }
}

public class ModerationState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Publishing document");
        doc.SetState(new PublishedState());
    }
}

public class PublishedState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Already published");
    }
}

El contexto mantiene el estado actual y le delega las acciones. Los objetos de estado pueden activar transiciones llamando a SetState() en el contexto:

public class Document
{
    private IDocumentState _state = new DraftState();
    
    public void SetState(IDocumentState state) => _state = state;
    
    public void Publish() => _state.Publish(this);
}

var doc = new Document();
doc.Publish();  // Pasando a moderación
doc.Publish();  // Publicando documento
doc.Publish();  // Ya publicado

El patrón State elimina las extensas sentencias if-else o switch que comprueban el estado actual. Cada clase de estado maneja solo su propio comportamiento, lo que hace que el código sea más fácil de mantener y extender con nuevos estados.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de semáforo utilizando el patrón State. Los semáforos pasan por distintos estados (rojo, amarillo, verde), y cada estado determina qué sucede cuando la luz cambia. En lugar de utilizar condicionales complejos, encapsularás cada estado de la luz en su propia clase.

Organizarás tu código en tres archivos:

  • TrafficLightState.cs: Define una interfaz ITrafficLightState en el espacio de nombres Traffic con un método Change(TrafficLight light). Luego crea tres clases de estado concretas:
    • RedState - cuando se llama a Change, imprime Red - Stop! Changing to Green... y transiciona el semáforo a GreenState
    • GreenState - imprime Green - Go! Changing to Yellow... y transiciona a YellowState
    • YellowState - imprime Yellow - Caution! Changing to Red... y transiciona a RedState
  • TrafficLight.cs: Crea una clase TrafficLight en el mismo espacio de nombres. Esta es tu clase de contexto que mantiene el estado actual. Debe comenzar en RedState por defecto y tener:
    • Un método SetState(ITrafficLightState state) que los objetos de estado utilizan para activar las transiciones
    • Un método Change() que delega al método Change del estado actual
  • Program.cs: Une todo creando un TrafficLight y ciclando a través de los cambios de estado basados en la entrada.

Recibirás una entrada:

  • El número de veces que se debe cambiar el semáforo (un número entero)

Crea un TrafficLight (que comienza en rojo) y llama a Change() el número especificado de veces.

Por ejemplo, si la entrada es 3, la salida debería ser:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...

Si la entrada es 5, el semáforo vuelve a ciclar:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...

Observa cómo la clase TrafficLight no contiene lógica sobre lo que significa cada color o qué viene después; todo ese conocimiento reside en las clases de estado individuales. ¡Cada estado es responsable de su propio comportamiento y de activar la transición al siguiente estado!

Hoja de referencia

El patrón State es un patrón de comportamiento que permite a un objeto cambiar su comportamiento cuando su estado interno cambia. En lugar de utilizar sentencias condicionales complejas, se encapsula cada estado en su propia clase y se delega el comportamiento al objeto de estado actual.

El patrón consta de tres componentes:

  • Interfaz State: Define el comportamiento específico del estado.
  • Clases de estado concretas: Implementan el comportamiento para cada estado.
  • Clase Context: Mantiene una referencia al estado actual.

Ejemplo de implementación:

// State interface
public interface IDocumentState
{
    void Publish(Document doc);
}

// Concrete state classes
public class DraftState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Moving to moderation");
        doc.SetState(new ModerationState());
    }
}

public class ModerationState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Publishing document");
        doc.SetState(new PublishedState());
    }
}

public class PublishedState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Already published");
    }
}

// Context class
public class Document
{
    private IDocumentState _state = new DraftState();
    
    public void SetState(IDocumentState state) => _state = state;
    
    public void Publish() => _state.Publish(this);
}

// Usage
var doc = new Document();
doc.Publish();  // Moving to moderation
doc.Publish();  // Publishing document
doc.Publish();  // Already published

El contexto mantiene el estado actual y le delega las acciones. Los objetos de estado pueden activar transiciones llamando a SetState() en el contexto. Esto elimina las extensas sentencias if-else o switch, haciendo que el código sea más fácil de mantener y extender con nuevos estados.

Pruébalo tú mismo

using System;
using Traffic;

class Program
{
    public static void Main(String[] args)
    {
        // Lee el número de veces que se debe cambiar el semáforo
        int n = Convert.ToInt32(Console.ReadLine());

        // TODO: Crea una instancia de TrafficLight (comienza en RedState por defecto)

        // TODO: Llama al método Change() n veces usando un bucle
    }
}
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