Introducción al Patrón State
El patrón State es un patrón de diseño de comportamiento que permite a un objeto cambiar su comportamiento cuando su estado interno cambia. Este patrón es particularmente útil cuando un objeto debe cambiar su comportamiento en tiempo de ejecución dependiendo de su estado.
Conceptos Clave
- Contexto: El objeto que contiene el estado y cuyo comportamiento cambia.
- Estado: Una interfaz o clase abstracta que define el comportamiento asociado con un estado particular del contexto.
- Estados Concretos: Implementaciones específicas de la interfaz de estado que definen el comportamiento para un estado particular del contexto.
Ejemplo Práctico
Vamos a implementar un ejemplo sencillo de una máquina expendedora que cambia su comportamiento basado en su estado (sin moneda, con moneda, vendiendo producto).
Diagrama de Clases
Clase | Descripción |
---|---|
VendingMachine | Clase Contexto que mantiene una referencia al estado actual. |
State | Interfaz que define el comportamiento común para todos los estados. |
NoCoinState | Estado concreto que representa la máquina sin moneda. |
HasCoinState | Estado concreto que representa la máquina con una moneda insertada. |
SoldState | Estado concreto que representa la máquina vendiendo un producto. |
Código
Interfaz State
public interface State { void insertCoin(); void ejectCoin(); void pressButton(); void dispense(); }
Clase Contexto: VendingMachine
public class VendingMachine { private State noCoinState; private State hasCoinState; private State soldState; private State currentState; public VendingMachine() { noCoinState = new NoCoinState(this); hasCoinState = new HasCoinState(this); soldState = new SoldState(this); currentState = noCoinState; // Estado inicial } public void setState(State state) { currentState = state; } public State getNoCoinState() { return noCoinState; } public State getHasCoinState() { return hasCoinState; } public State getSoldState() { return soldState; } public void insertCoin() { currentState.insertCoin(); } public void ejectCoin() { currentState.ejectCoin(); } public void pressButton() { currentState.pressButton(); currentState.dispense(); } }
Estados Concretos
NoCoinState
public class NoCoinState implements State { private VendingMachine vendingMachine; public NoCoinState(VendingMachine vendingMachine) { this.vendingMachine = vendingMachine; } @Override public void insertCoin() { System.out.println("Coin inserted."); vendingMachine.setState(vendingMachine.getHasCoinState()); } @Override public void ejectCoin() { System.out.println("No coin to eject."); } @Override public void pressButton() { System.out.println("Insert coin first."); } @Override public void dispense() { System.out.println("No coin inserted."); } }
HasCoinState
public class HasCoinState implements State { private VendingMachine vendingMachine; public HasCoinState(VendingMachine vendingMachine) { this.vendingMachine = vendingMachine; } @Override public void insertCoin() { System.out.println("Coin already inserted."); } @Override public void ejectCoin() { System.out.println("Coin ejected."); vendingMachine.setState(vendingMachine.getNoCoinState()); } @Override public void pressButton() { System.out.println("Button pressed."); vendingMachine.setState(vendingMachine.getSoldState()); } @Override public void dispense() { System.out.println("No product dispensed."); } }
SoldState
public class SoldState implements State { private VendingMachine vendingMachine; public SoldState(VendingMachine vendingMachine) { this.vendingMachine = vendingMachine; } @Override public void insertCoin() { System.out.println("Please wait, we're already giving you a product."); } @Override public void ejectCoin() { System.out.println("Sorry, you already pressed the button."); } @Override public void pressButton() { System.out.println("Button already pressed."); } @Override public void dispense() { System.out.println("Dispensing product."); vendingMachine.setState(vendingMachine.getNoCoinState()); } }
Ejercicio Práctico
Ejercicio
Implementa una máquina de café que tiene los siguientes estados: NoCoinState
, HasCoinState
, BrewingState
, y SoldOutState
. La máquina debe permitir insertar una moneda, devolver la moneda, seleccionar un tipo de café y dispensar el café.
Solución
- Define la interfaz
State
con los métodos necesarios. - Implementa la clase
CoffeeMachine
que actúa como el contexto. - Implementa los estados concretos (
NoCoinState
,HasCoinState
,BrewingState
,SoldOutState
).
Retroalimentación y Errores Comunes
-
Error Común: No cambiar el estado del contexto después de una acción.
- Solución: Asegúrate de que cada acción en un estado concreto cambie el estado del contexto si es necesario.
-
Error Común: Implementar lógica específica del estado en el contexto.
- Solución: Mantén la lógica específica del estado dentro de las clases de estado concreto.
Conclusión
El patrón State es una poderosa herramienta para manejar cambios en el comportamiento de un objeto basado en su estado interno. Al separar los estados en clases concretas, se mejora la mantenibilidad y extensibilidad del código. En el siguiente módulo, exploraremos el patrón Strategy, que permite definir una familia de algoritmos y hacer que sean intercambiables.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil