Patrón State como patrón de diseño en Java
En esta entrada sobre patrones de diseño vamos a ver el Patrón State o patrón de estado mediante un sencillo ejemplo codificado en Java. Este patrón que se clasifica dentro de los patrones de comportamiento.
La idea del Patrón State es crear objetos que representan los diferentes estados y un objeto que será el contexto que variará su comportamiento en función del estado del objeto.
Lo mejor para entenderlo es verlo con un ejemplo.
Ejemplo de Patrón State
Vamos a crear un ejemplo basado en los estados de una persona con una tarjeta que quiere realizar compras en una tienda, y en función de esos estados podremos realizar unas u otras acciones. Los estados son:
- BLOQUEADA: No se podrá realizar ninguna acción, estado después de Desactivada
- ACTIVA: Activa puedes realizar las acciones de comprar.
- DESACTIVADA: Desactivada no se podrá realizar ninguna acción, previo a bloqueada
- COMPRANDO: Estado activo.
Vamos a dividir el ejemplo en 4 clases. La clase principal contiene una referencia al estado del objeto, la cual se encargará de realizar parte del trabajo. Algunas acciones involucran la sustitución del estado del objeto por otro.
Cada clase que vamos a definir tendrá un estado definido, a parte definiremos una clase abstracta en la que se tendrás los estados a definir.
Cada estado podrá realizar una serie de acciones (en el ejemplo solo veremos transicciones), que sería lo lógico en una aplicación real.
Clase principal State
La clase principal State es una clase abstracta que contendrá las «referencias» a todos los estados en los que una tarjeta de crédito se encontrará.
package com.refactorizando.statepattern.example; public abstract class State { User user; State(User user) { this.user = user; } public abstract String onActive(); public abstract String onDisable(); public abstract String onLock(); public abstract String onBuy(); }
Clase Activa
En este estado se permitirá realizar compras y será notificado que la tarjeta esta activa.
package com.refactorizando.statepattern.example; public class ActiveState extends State{ public ActiveState(User user) { super(user); } @Override public String onActive() { user.changeState(new BuyingState(user)); return "Actived ..."; } @Override public String onDisable() { user.changeState(new DisableState(user)); return "Disabled..."; } @Override public String onLock() { user.changeState(new LockState(user)); return "Locked..."; } @Override public String onBuy() { String action = user.startBuy(); user.changeState(new BuyingState(user)); return action; } }
Clase de Estado desactivado
En el estado desactivado se notificará al usuario que su tarjeta ha sido desactivada cualquier compra realizada será bloqueada.
package com.refactorizando.statepattern.example; public class DisableState extends State{ DisableState(User user) { super(user); user.setBuying(false); user.setEnable(false); } @Override public String onActive() { user.changeState(new ActiveState(user)); return "Disabled..."; } @Override public String onLock() { user.changeState(new ActiveState(user)); return "Disable locked..."; } @Override public String onDisable() { if (user.isBuying()) { user.changeState(new ActiveState(user)); return "Stop buying"; } else { return "Disabled..."; } } @Override public String onBuy() { user.changeState(new ActiveState(user)); return "Disabled temporarily..."; } }
Estado Bloqueado
El estado bloqueado será el paso previo al estado Desactivado, en caso de que esta comprando se cancelará la compra. Si previamente no esta desactivada el paso previo será realizar esa desactivación.
package com.refactorizando.statepattern.example; public class LockState extends State{ LockState(User user) { super(user); } @Override public String onActive() { return "Locked..."; } @Override public String onDisable() { return "Locked..."; } @Override public String onLock() { if (user.isBuying()){ user.changeState(new DisableState(user)); return "Locked..."; } if (user.getEnable()){ user.changeState(new DisableState(user)); return "Disabled..."; } user.changeState(new ActiveState(user)); return "Locked..."; } @Override public String onBuy() { return "Locked..."; } }
Estado Comprando
Todo esta correcto y el usuario puede comprar teniendo el estado de comprando.
package com.refactorizando.statepattern.example; public class BuyingState extends State{ BuyingState(User user) { super(user); user.setBuying(true); } @Override public String onActive() { user.changeState(new ActiveState(user)); return "Active..."; } @Override public String onDisable() { user.changeState(new DisableState(user)); return "Stop buying"; } @Override public String onLock() { user.changeState(new LockState(user)); return "Stop buying"; } @Override public String onBuy() { user.changeState(new BuyingState(user)); return "buying"; } }
Conclusión
Dentro de los patrones de diseño en Java el Patrón State, nos va a ayudar a simplificar y a ver de una manera más fácil e intuitiva de los diferentes estados en los que nos vamos a encontrar.
Este ha sido un ejemplo sencillo donde no hemos añadido mucha lógica, lo más importante es ver que cada clase tiene un estado por el que se transita y una clase padre que «orquesta» esa transición. Si quieres ver el ejemplo completo puedes echar un vistazo en nuestro Github.
Si necesitas más información puedes escribirnos un comentario o un correo electrónico a refactorizando.web@gmail.com o también nos puedes contactar por nuestras redes sociales Facebook o twitter y te ayudaremos encantados!
hola, se podría hacer con spring boot?
Sí, en el ejemplo que hay en github podrías añadir el framework de spring en el pom.xml crear la clase main de spring y convertir las clases en bean para su instanciación
Puedes compartir el link de GitHub. Pues al ejercicio le falta codigo, quizas ahi está completo. Gracias por el aporte.
Hola Gabriel H
Claro: https://github.com/refactorizando-web/patterns