Menu
Coddy logo textTech

Patrón State

Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 53 de 64.

El patrón State permite que un objeto cambie su comportamiento cuando cambia su estado interno. El objeto parece cambiar su clase según su estado actual.

Aquí tienes clases de estado sencillas para un semáforo:

class RedState:
    def next_state(self, light):
        print("Red -> Green")
        light.state = GreenState()
    
    def current_color(self):
        return "Red"

class GreenState:
    def next_state(self, light):
        print("Green -> Yellow")
        light.state = YellowState()
    
    def current_color(self):
        return "Green"

class YellowState:
    def next_state(self, light):
        print("Yellow -> Red")
        light.state = RedState()
    
    def current_color(self):
        return "Yellow"

Cada estado define qué sucede al pasar al siguiente estado.

Crea una clase de contexto que contenga el estado actual:

class TrafficLight:
    def __init__(self):
        self.state = RedState()  # Empieza con rojo
    
    def change(self):
        self.state.next_state(self)
    
    def get_color(self):
        return self.state.current_color()

El semáforo delega el comportamiento a su objeto de estado actual.

Usa el semáforo:

light = TrafficLight()
print(f"Current: {light.get_color()}")

light.change()  # Rojo -> Verde
print(f"Current: {light.get_color()}")

light.change()  # Verde -> Amarillo
print(f"Current: {light.get_color()}")

light.change()  # Amarillo -> Rojo
print(f"Current: {light.get_color()}")

Crea otro ejemplo con un reproductor sencillo:

class PlayingState:
    def play(self, player):
        print("Already playing")
    
    def stop(self, player):
        print("Stopping music")
        player.state = StoppedState()

class StoppedState:
    def play(self, player):
        print("Starting music")
        player.state = PlayingState()
    
    def stop(self, player):
        print("Already stopped")

class MusicPlayer:
    def __init__(self):
        self.state = StoppedState()
    
    def play(self):
        self.state.play(self)
    
    def stop(self):
        self.state.stop(self)

player = MusicPlayer()
player.play()   # Iniciando música
player.play()   # Ya se está reproduciendo
player.stop()   # Deteniendo música
player.stop()   # Ya está detenido

Salida:

Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stopped

Punto clave: el patrón State encapsula el comportamiento específico de cada estado en clases separadas y permite que el objeto de contexto delegue en el estado actual. Cuando cambia el estado, el comportamiento cambia automáticamente. Esto elimina las instrucciones complejas de if/else y facilita la incorporación de nuevos estados.

challenge icon

Desafío

Fácil

Implementa el patrón State en state.py para una lámpara con un botón. Cada pulsación hace que la lámpara pase por tres estados en un ciclo: apagada, baja, alta y vuelva a apagada. En lugar de una cadena de if sobre una cadena, cada estado es su propio objeto que sabe qué ocurre cuando se pulsa el botón.

  • LampState es la clase base con press(lamp) y describe().
  • OffState, LowState y HighState los implementan: press llama a lamp.set_state(...) con el estado siguiente (de apagada a baja, de baja a alta y de alta a apagada), y describe devuelve Lamp is off, Lamp is on low o Lamp is on high.
  • Lamp es el contexto: comienza en OffState, set_state intercambia el objeto de estado, press_button delega en el estado actual y status devuelve la descripción actual.

driver.py está bloqueado: pulsa el botón e imprime el estado. Observa que Lamp nunca comprueba en qué estado se encuentra; los objetos de estado toman la decisión.

Pruébalo tú mismo

from state import Lamp

# Manejador de casos de prueba (no cambiar)
test_case = input()
lamp = Lamp()

if test_case == "initial_test":
    print(lamp.status())
elif test_case == "one_press_test":
    lamp.press_button()
    print(lamp.status())
elif test_case == "cycle_test":
    for _ in range(4):
        print(lamp.status())
        lamp.press_button()
elif test_case == "many_presses_test":
    for _ in range(7):
        lamp.press_button()
    print(lamp.status())
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 Python online