Patrón State
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 74 de 87.
El patrón State es un patrón de diseño de comportamiento que permite que un objeto cambie su comportamiento cuando cambia su estado interno. El objeto parece cambiar de clase, pero en realidad delega el comportamiento en distintos objetos de estado. Piensa en una máquina expendedora: su respuesta al pulsar un botón depende de si está inactiva, tiene dinero insertado o está dispensando un producto.
En lugar de usar instrucciones condicionales complejas para gestionar diferentes estados, encapsulas cada estado en su propia clase. El patrón implica un Contexto que mantiene una referencia al estado actual y clases State que definen el comportamiento de cada estado:
interface State {
void handle(Context context);
}
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}Cada estado concreto implementa el comportamiento y puede activar transiciones a otros estados:
class IdleState implements State {
public void handle(Context context) {
System.out.println("Idle: Insert coin to start");
context.setState(new ActiveState());
}
}
class ActiveState implements State {
public void handle(Context context) {
System.out.println("Active: Processing...");
context.setState(new IdleState());
}
}El contexto delega las solicitudes a su estado actual, y el comportamiento cambia automáticamente a medida que cambia el estado:
Context context = new Context();
context.setState(new IdleState());
context.request(); // Idle: Inserta una moneda para empezar
context.request(); // Active: Procesando...El patrón State es ideal cuando el comportamiento de un objeto depende en gran medida de su estado y debe cambiar durante la ejecución. Elimina grandes bloques condicionales y facilita la adición de nuevos estados; solo tienes que crear una nueva clase que implemente la interfaz State.
Desafío
Fácil¡Construyamos un sistema de flujo de trabajo de documentos usando el patrón State! Crearás un sistema que modela cómo un documento pasa por distintas etapas, Draft, Review y Published, donde cada estado determina qué acciones están disponibles y cómo se comporta el documento cuando intentas editarlo o aprobarlo.
Organizarás tu código en cuatro archivos:
DocumentState.java: Define la interfazDocumentStateque implementarán todos los estados. Debe declarar dos métodos:edit(Document doc)para intentar editar el documento yapprove(Document doc)para intentar aprobarlo o avanzarlo a la siguiente etapa.States.java: Crea tres clases de estado concretas que implementenDocumentState:DraftState: cuando se llama aedit, imprimeEditing draft.... Cuando se llama aapprove, imprimeDraft approved. Moving to review.y cambia el documento al estadoReviewState.ReviewState: cuando se llama aedit, imprimeCannot edit during review.(no cambia el estado). Cuando se llama aapprove, imprimeReview complete. Publishing document.y cambia al estadoPublishedState.PublishedState: cuando se llama aedit, imprimeCannot edit published document.. Cuando se llama aapprove, imprimeDocument already published.. Ninguna de las dos acciones cambia el estado.Document.java: Crea la clase de contexto que mantiene el estado actual. TuDocumentdebe tener:Un campo privado que contenga el
DocumentStateactual, inicializado enDraftStatedentro del constructor.Un método
setState(DocumentState state)que cambie el estado actual.Un método
edit()que delegue en el métodoeditdel estado actual.Un método
approve()que delegue en el métodoapprovedel estado actual.Un método
getStatus()que devuelva el nombre simple de la clase del estado actual (usagetClass().getSimpleName()).Main.java: ¡Demuestra tu sistema de estados! Recibirás una entrada: una secuencia de acciones en forma de cadena separada por comas, donde cada acción eseditoapprove(por ejemplo:edit,approve,edit,approve).Crea un
Documente imprime su estado inicial con el formatoStatus: [state]. Después, procesa cada acción en orden y llama al método correspondiente del documento. Después de cada acción, imprime el estado actual.
Recibirás una entrada: una cadena de acciones separadas por comas.
Por ejemplo, con la entrada edit,approve,approve, el resultado sería:
Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedStateObserva cómo la misma llamada a approve() produce resultados diferentes según el estado actual del documento. ¡Esta es la esencia del patrón State! El documento no usa condicionales para comprobar su estado; en su lugar, delega el comportamiento en el objeto de estado actual, que gestiona la acción adecuadamente y activa las transiciones cuando es necesario.
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Crea un nuevo Document
// TODO: Imprime el estado inicial en formato "Status: [state]"
// TODO: Divide la entrada por comas para obtener las acciones individuales
// TODO: Recorre cada acción
// - Si la acción es "edit", llama a edit() en document
// - Si la acción es "approve", llama a approve() en document
// - Después de cada acción, imprime el estado actual
}
}
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 OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón IteratorPractica por tu cuenta: Compilador de Java online