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 de 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 lo que sucede al pasar al siguiente estado.
Crea una clase de contexto que almacene 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 la música
player.play() # Ya está sonando
player.stop() # Deteniendo la música
player.stop() # Ya está detenidoSalida:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedPunto 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 complejas sentencias if/else y facilita añadir nuevos estados.
Desafío
FácilImplementa 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: apagado, bajo, alto y de nuevo a apagado. En lugar de una cadena de if sobre una cadena de texto, cada estado es su propio objeto, que sabe qué ocurre cuando se pulsa el botón.
LampStatees la clase base conpress(lamp)ydescribe().OffState,LowStateyHighStatelos implementan:pressllama alamp.set_state(...)con el siguiente estado (de apagado a bajo, de bajo a alto y de alto a apagado), ydescribedevuelveLamp is off,Lamp is on lowoLamp is on high.Lampes el contexto: comienza enOffState,set_statecambia el objeto de estado,press_buttondelega en el estado actual ystatusdevuelve la descripción actual.
driver.py está bloqueado: pulsa el botón e imprime el estado. Fíjate en que Lamp nunca comprueba en qué estado se encuentra; los objetos de estado deciden.
Pruébalo tú mismo
from state import Lamp
# Gestor de casos de prueba (no modificar)
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())
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
1Fundamentos de la POO
Introducción a la POOArchivos externosClases vs. objetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Repaso: calculadora sencilla4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosRepaso: jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso: lista personalizada10Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy2Decoradores
Introducción a los decoradoresDecorador de propiedadDecorador de método estáticoDecorador de método de clase5Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas8Conceptos avanzados de POO
Composición frente a herenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs. variables de claseDecoradores de propiedadesAtributos privadosRepaso: gestor de cuentas bancariasPractica por tu cuenta: Compilador de Python online