Patrón State como patrón de diseño en Java

State Pattern

State Pattern


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.

Patrón State como Patrón de Diseño en Java | State Pattern
State Pattern

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 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!


2 pensamientos sobre “Patrón State como patrón de diseño en Java

    1. 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

Deja una respuesta

Tu dirección de correo electrónico no será publicada.