Patrón State
Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 54 de 65.
El patrón State proporciona a un objeto un objeto de estado independiente para cada modo en el que puede estar. El objeto delega su trabajo en el estado actual, por lo que su comportamiento cambia cuando cambia el estado.
Para unos pocos estados, un enum y un match son suficientes. Cuando cada estado reacciona a varias acciones a su manera, ese match crece con cada estado y cada acción. El patrón State traslada las reglas de cada estado a su propia clase:
# hero_state.gd
@abstract
class_name HeroState
extends RefCounted
@abstract func get_state_name() -> String
@abstract func handle(action: String) -> HeroStatehandle() devuelve el siguiente estado: un nuevo objeto de estado al que cambiar, o self para quedarse.
# idle_state.gd
class_name IdleState
extends HeroState
func get_state_name() -> String:
return "Idle"
func handle(action: String) -> HeroState:
if action == "run":
return RunState.new()
return selfRunState se escribe de la misma manera: su nombre es "Running", y "stop" devuelve IdleState.new(). El héroe, el contexto, conserva el estado actual y le pregunta qué hacer:
# hero.gd
class_name Hero
extends RefCounted
var state: HeroState = IdleState.new()
func handle_action(action: String) -> void:
var next := state.handle(action)
if next != state:
print(state.get_state_name(), " -> ", next.get_state_name())
state = next# main.gd
var hero := Hero.new()
for action in ["stop", "run", "run", "stop"]:
hero.handle_action(action)Idle -> Running
Running -> IdleLa misma acción significa cosas diferentes en distintos estados: "stop" no hace nada mientras está inactivo y detiene a un héroe que está corriendo. Cada regla reside en la clase de su estado, así que un estado nuevo, como saltar, es una clase nueva.
Los estados devuelven el siguiente estado en lugar de almacenar al héroe. Un estado que mantuviera al héroe mientras el héroe mantiene el estado formaría un ciclo de referencias, y ninguno de los dos objetos se liberaría nunca.
Desafío
FácilUna puerta está Locked, Closed o Open. DoorState (door_state.gd) declara get_state_name() y handle(action), y LockedState (locked_state.gd) ya está escrito: unlock hace que la puerta quede Closed. Escribe:
ClosedState.handle():opendevuelve un nuevoOpenState,lockuno nuevoLockedState, y cualquier otra cosa,self.OpenState.handle():closedevuelve un nuevoClosedState, y cualquier otra cosa,self.Door.handle_action(action): pregunta al estado actual cuál es el siguiente. Si es el mismo objeto, imprimeACTION: still STATE; de lo contrario, imprimeACTION: OLD -> NEWy cambia al nuevo estado.
La puerta empieza en Locked. El código proporcionado lee cuántas acciones siguen, luego una acción por línea, e imprime el estado final. Para open, unlock, open, lock el resultado es:
open: still Locked
unlock: Locked -> Closed
open: Closed -> Open
lock: still Open
Final state: OpenTu código va en door.gd, closed_state.gd y open_state.gd. main.gd contiene el código proporcionado para la entrada y salida, y no se puede editar.
Pruébalo tú mismo
extends Node
func _ready():
# Código de entrada/salida proporcionado: mantenlo tal como está
var door := Door.new()
var count := int(OS.read_string_from_stdin())
for i in count:
door.handle_action(OS.read_string_from_stdin())
print("Final state: ", door.state.get_state_name())
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 programación orientada a objetos
Archivos externosIntroducción a la programación orientada a objetosClases vs. objetosLa palabra clave selfMétodosPropiedadesConstructor (_init)Repaso: calculadora sencilla4Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas7Señales
¿Qué es una señal?Declarar y emitirConectarse a las señalesSeñales con argumentosRepaso: sistema de salud10Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite2Propiedades de clase
Variables de instancia y estáticasFunciones estáticasMétodos setter de propiedadesMétodos getter de propiedadesPrivado por convenciónRepaso: administrador de cuentas bancarias5Encapsulación
Miembros públicos y privadosValidación con settersOcultación de informaciónPropiedades de solo lecturaRepaso: sistema de registros de estudiantes8Conceptos avanzados de POO
Composición frente a herenciaClases internasNodos como componentesRefCounted frente a NodeEnums en clases3Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosCadenas de herenciaComprobaciones de tipo con isRepaso: jerarquía de empleados6Métodos especiales
Introducción a los métodos virtualesEl método _to_stringIteradores personalizadosRepaso: lista personalizada9Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de GDScript online