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á 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 instrucciones complejas de if/else y facilita la incorporación de 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: 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.
LampStatees la clase base conpress(lamp)ydescribe().OffState,LowStateyHighStatelos implementan:pressllama alamp.set_state(...)con el estado siguiente (de apagada a baja, de baja a alta y de alta a apagada), ydescribedevuelveLamp is off,Lamp is on lowoLamp is on high.Lampes el contexto: comienza enOffState,set_stateintercambia 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. 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())
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
Archivos externosIntroducción a la POOClases vs ObjetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Resumen - Calculadora simple4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosResumen - 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 propertyDecorador de métodos estáticosDecorador de métodos de clase5Polimorfismo
Sobreescritura de métodos revisitadaDuck TypingClases y métodos abstractosDiseño de interfacesResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. 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 de claseDecoradores de propiedadesAtributos privadosResumen - Gestor de cuentas bancariasPractica por tu cuenta: Compilador de Python online