Menu
Coddy logo textTech

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 de Estado (State Pattern) es un patrón de diseño de comportamiento que permite que un objeto cambie su comportamiento cuando su estado interno cambia. El objeto parece cambiar su clase, pero en realidad, delega el comportamiento a diferentes objetos de estado. Piense en una máquina expendedora: su respuesta al presionar un botón depende de si está inactiva, si se ha insertado dinero o si está dispensando un producto.

En lugar de utilizar sentencias condicionales complejas para manejar diferentes estados, encapsulas cada estado en su propia clase. El patrón involucra un Context que mantiene una referencia al estado actual, y clases State que definen el comportamiento para 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 peticiones a su estado actual, y el comportamiento cambia automáticamente a medida que el estado cambia:

Context context = new Context();
context.setState(new IdleState());

context.request();  // Inactivo: Inserte moneda para comenzar
context.request();  // Activo: Procesando...

El patrón State es ideal cuando el comportamiento de un objeto depende en gran medida de su estado y debe cambiar en tiempo de ejecución. Elimina grandes bloques condicionales y hace que añadir nuevos estados sea sencillo: solo hay que crear una nueva clase que implemente la interfaz State.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de flujo de trabajo de documentos utilizando el Patrón State! Crearás un sistema que modela cómo un documento se mueve a través de diferentes 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 interfaz DocumentState que implementarán todos los estados. Debe declarar dos métodos: edit(Document doc) para intentar editar el documento, y approve(Document doc) para intentar aprobar/avanzar el documento a la siguiente etapa.
  • States.java: Crea tres clases de estado concretas que implementen DocumentState:

    DraftState - Cuando se llama a edit, imprime Editing draft.... Cuando se llama a approve, imprime Draft approved. Moving to review. y transiciona el documento a ReviewState.

    ReviewState - Cuando se llama a edit, imprime Cannot edit during review. (sin cambio de estado). Cuando se llama a approve, imprime Review complete. Publishing document. y transiciona a PublishedState.

    PublishedState - Cuando se llama a edit, imprime Cannot edit published document.. Cuando se llama a approve, imprime Document already published.. Ninguna acción cambia el estado.

  • Document.java: Crea la clase de contexto que mantiene el estado actual. Tu Document debe tener:

    Un campo privado que contenga el DocumentState actual, inicializado a DraftState en el constructor.

    Un método setState(DocumentState state) que cambie el estado actual.

    Un método edit() que delegue en el método edit del estado actual.

    Un método approve() que delegue en el método approve del estado actual.

    Un método getStatus() que devuelva el nombre simple de la clase del estado actual (usa getClass().getSimpleName()).

  • Main.java: ¡Demuestra tu sistema de estados! Recibirás una entrada: una secuencia de acciones como una cadena separada por comas donde cada acción es edit o approve (por ejemplo: edit,approve,edit,approve).

    Crea un Document e imprime su estado inicial en el formato Status: [state]. Luego procesa cada acción en orden, llamando al método apropiado en el documento. Después de cada acción, imprime el estado actual.

Recibirás una entrada: una cadena de acciones separada por comas.

Por ejemplo, con la entrada edit,approve,approve, tu salida sería:

Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedState

Observa cómo la misma llamada a approve() produce resultados diferentes dependiendo del estado actual del documento—¡esta es la esencia del Patrón State! El documento no utiliza condicionales para verificar su estado; en su lugar, delega el comportamiento al objeto de estado actual, que maneja la acción de manera apropiada y activa las transiciones cuando es necesario.

Hoja de referencia

El Patrón State es un patrón de diseño de comportamiento que permite que un objeto cambie su comportamiento cuando su estado interno cambia, delegando el comportamiento a diferentes objetos de estado en lugar de utilizar sentencias condicionales complejas.

El patrón consiste en un Contexto que mantiene una referencia al estado actual, y clases de Estado que definen el comportamiento para 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 peticiones 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: Insert coin to start
context.request();  // Active: Processing...

El Patrón State es ideal cuando el comportamiento de un objeto depende en gran medida de su estado y debe cambiar en tiempo de ejecución. Elimina grandes bloques condicionales y hace que añadir nuevos estados sea sencillo.

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: Crear un nuevo Documento
        
        // TODO: Imprimir el estado inicial en formato "Status: [state]"
        
        // TODO: Dividir la entrada por coma para obtener acciones individuales
        
        // TODO: Recorrer cada acción
        // - Si la acción es "edit", llamar a edit() en el documento
        // - Si la acción es "approve", llamar a approve() en el documento
        // - Después de cada acción, imprimir el estado actual
    }
}
quiz iconPonte a prueba

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