Patrón State
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 98 de 110.
El patrón State permite que un objeto cambie su comportamiento cuando cambia su estado interno, haciendo que parezca como si el objeto hubiera cambiado de clase. En lugar de utilizar condicionales complejos para manejar diferentes estados, encapsulas cada estado en su propia clase y delegas el comportamiento al objeto de estado actual.
El patrón consiste en un Context que mantiene una referencia al estado actual, y clases State que definen el comportamiento para cada estado posible. Cuando el estado del contexto cambia, su comportamiento cambia automáticamente:
abstract class DocumentState {
void publish(Document doc);
String getStatus();
}
class DraftState implements DocumentState {
@override
void publish(Document doc) {
print('Moving to review...');
doc.setState(ReviewState());
}
@override
String getStatus() => 'Draft';
}
class ReviewState implements DocumentState {
@override
void publish(Document doc) {
print('Document published!');
doc.setState(PublishedState());
}
@override
String getStatus() => 'Under Review';
}
class PublishedState implements DocumentState {
@override
void publish(Document doc) {
print('Already published.');
}
@override
String getStatus() => 'Published';
}
class Document {
DocumentState _state = DraftState();
void setState(DocumentState state) => _state = state;
void publish() => _state.publish(this);
String getStatus() => _state.getStatus();
}
void main() {
var doc = Document();
print(doc.getStatus()); // Borrador (Draft)
doc.publish(); // Pasando a revisión... (Moving to review...)
print(doc.getStatus()); // En revisión (Under Review)
doc.publish(); // ¡Documento publicado! (Document published!)
print(doc.getStatus()); // Publicado (Published)
}Cada clase de estado maneja la acción publish() de manera diferente y puede realizar la transición del documento al siguiente estado. La clase Document no necesita condicionales para verificar su estado actual; simplemente delega en cualquier objeto de estado que esté activo en ese momento. Este patrón es ideal para objetos con distintos modos de comportamiento, como el procesamiento de pedidos, reproductores multimedia o sistemas de flujo de trabajo.
Desafío
Fácil¡Vamos a construir un sistema de semáforo utilizando el patrón State! Crearás un semáforo que cicla a través de diferentes estados, donde cada estado determina el color de la luz y cómo transiciona al siguiente estado.
Organizarás tu código en dos archivos:
traffic_light.dart: Este archivo contiene tus clases de estado y el contexto del semáforo. Crea una clase abstractaTrafficLightStatecon dos métodos:String getColor()que devuelve el color actual de la luz, yvoid next(TrafficLight light)que transiciona el semáforo a su siguiente estado. Implementa tres clases de estado concretas:RedState- devuelveREDcomo su color e imprimeStop! Light is red.cuando se llama anext(), luego transiciona aGreenStateGreenState- devuelveGREENcomo su color e imprimeGo! Light is green.cuando se llama anext(), luego transiciona aYellowStateYellowState- devuelveYELLOWcomo su color e imprimeCaution! Light is yellow.cuando se llama anext(), luego transiciona aRedState
TrafficLight(el contexto) que comience enRedState. Debe tener un métodosetState()para cambiar el estado actual, un métodogetColor()que delegue en el estado actual, y un métodochange()que llame anext()en el estado actual.main.dart: Importa tu archivo de semáforo y demuestra el patrón State en acción. Crea unTrafficLighte imprime su color inicial. Luego llama achange()tres veces, imprimiendo el color después de cada cambio. Esto mostrará el semáforo ciclando a través de todos los estados y volviendo al principio.
¡Observa cómo la clase TrafficLight no necesita condicionales para determinar el comportamiento - cada estado conoce su propio color y qué estado sigue! ¡El semáforo simplemente delega en cualquier estado que esté activo actualmente!
Salida esperada:
RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
REDHoja de referencia
El patrón State permite que un objeto cambie su comportamiento cuando cambia su estado interno. En lugar de utilizar condicionales complejos, cada estado se encapsula en su propia clase.
El patrón consta de:
- Contexto: Mantiene una referencia al estado actual
- Clases de estado: Definen el comportamiento para cada estado posible
Estructura básica:
abstract class DocumentState {
void publish(Document doc);
String getStatus();
}
class DraftState implements DocumentState {
@override
void publish(Document doc) {
print('Moving to review...');
doc.setState(ReviewState());
}
@override
String getStatus() => 'Draft';
}
class Document {
DocumentState _state = DraftState();
void setState(DocumentState state) => _state = state;
void publish() => _state.publish(this);
String getStatus() => _state.getStatus();
}El contexto delega el comportamiento al objeto de estado actual. Cada clase de estado maneja las acciones de manera diferente y puede realizar la transición al siguiente estado. Esto elimina la necesidad de condicionales para verificar el estado actual.
Ideal para objetos con distintos modos de comportamiento, como el procesamiento de pedidos, reproductores multimedia o sistemas de flujo de trabajo.
Pruébalo tú mismo
import 'traffic_light.dart';
void main() {
// TODO: Crear una instancia de TrafficLight
// TODO: Imprimir el color inicial
// TODO: Llamar a change() e imprimir el color (3 veces para recorrer todos los estados)
// Primer cambio: RED -> GREEN
// Segundo cambio: GREEN -> YELLOW
// Tercer cambio: YELLOW -> RED
}
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 POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository