5 votes

Comment mettre en œuvre le modèle de conception d'état dans un modèle de domaine JPA ?

Je veux mettre en œuvre le modèle de conception d'état dans JPA. La façon dont je procède actuellement est décrite dans ce qui suit article de blog .

L'auteur utilise un enum contenant toutes les implémentations d'état disponibles au lieu de créer une classe/interface abstraite pour l'abstraction d'état et d'écrire une implémentation pour chaque état. Je trouve cette approche très utile, car les enums peuvent être facilement sérialisés dans JPA et vous pouvez stocker l'état actuel de votre objet sans effort supplémentaire. J'ai également imbriqué l'interface d'état et toutes les classes d'état dans l'enum en les rendant privées, puisqu'elles sont spécifiques à l'implémentation et ne doivent pas être visibles par un client. Voici un exemple de code de l'enum :

public enum State {

  STATE_A(new StateA()),
  STATE_B(new StateB());

  private final StateTransition state;

  private State(StateTransition state) {
     this.state = state;
  }

  void transitionA(Context ctx) {
    state.transitionA(ctx);
  }

  void transitionB(Context ctx) {
     state.transitionB(ctx);
  }

  private interface StateTransition {

    void transitionA(Context ctx);

    void transitionB(Context ctx);
  }

  private static class StateA implements StateTransition {

    @Override
    public void transitionA(Context ctx) {
        // do something
    ctx.setState(STATE_B);
    }

    @Override
    public void transitionB(Context ctx) {
        // do something
    ctx.setState(STATE_A);
    }
  }

  private static class StateB implements StateTransition {

    @Override
    public void transitionA(Context ctx) {
    throw new IllegalStateException("transition not allowed");
    }

    @Override
    public void transitionB(Context ctx) {
        // do something
    ctx.setState(STATE_A);
    }
  }
}

J'aimerais vous en faire part et recueillir votre avis à ce sujet. Trouvez-vous cela utile ? Comment implémenteriez-vous le design pattern state dans un modèle de domaine JPA ?

0voto

user3293409 Points 23

C'est une vieille question, mais pour ceux qui pourraient chercher dans les archives, j'ai utilisé la machine à états de Spring avec des enums (au lieu de Strings).

En ce qui concerne la gestion des transitions, il existe des annotations qui permettent à vos fonctions d'être appelées lorsqu'une transition se produit.

1.1.0.RELEASE donne un mécanisme par défaut pour persister un état en persistance du StateMachineContext et une alternative utilisant recette persistante .

Si l'on se réfère à JPA, il est possible de disposer d'un Listener d'entité qui initialisera la machine d'état le jour de l'événement. postload (@Postload), je pense que ce n'est pas une bonne voie à suivre.

0voto

En corollaire, ce modèle AspectJ combiné à des classes Enum spécifiques aux constantes est également utile. Je ne montrerai pas l'intégration de Spring ici, car je me concentre uniquement sur AspectJ. Mais je pense que nous pouvons aussi utiliser Spring avec AspectJ.

Un autre point est que les modèles OO peuvent être puissants pour ce cas d'utilisation. Je montre ce modèle uniquement parce que la question renvoie à l'article du blog qui contient un lien vers un exemple de Spring et AspectJ.

Et j'ai également besoin d'utiliser de bons modèles OO avec JPA.

public interface StateTransition {

StateTransition activate();

StateTransition deActivate();

}

public enum AStateTransition implements StateTransition{

ACTIVATE(new Activation()),

DEACTIVATE(new DeActivation());

private final StateTransition stateTransition;

private AStateTransition(StateTransition stateTransition) {
    this.stateTransition = stateTransition;
}

@Override
public StateTransition activate() {
    return stateTransition.activate();
}

@Override
public StateTransition deActivate() {
    return stateTransition.deActivate();
}
}

public class Activation implements StateTransition {

@Override
public StateTransition activate() {
    return AStateTransition.ACTIVATE;
}

@Override
public StateTransition deActivate() {
    return AStateTransition.DEACTIVATE;
}
}

public class DeActivation implements StateTransition {

@Override
public StateTransition deActivate() {
    return AStateTransition.DEACTIVATE;
}

@Override
public StateTransition activate() {
    return AStateTransition.ACTIVATE;
}
}

 @Aspect()

 public class StateChangeAspect {

    //Could be more generic so that all implemented methods
    //are covered
    @Pointcut("execution(* AStateTransition.activate()) && target(stateTransition) && if()")

    public static boolean stateChangePointcut( AStateTransition stateTransition ){
        return AStateTransition.ACTIVATE == stateTransition;
    }

    @Before("stateChangePointcut(stateTransition)")
    public void test1( AStateTransition stateTransition ) {
        System.out.println( " aspect  " );
    }

    @Before("stateChangePointcut(stateTransition)")
    public void test1(JoinPoint joinPoint, AStateTransition stateTransition) {
      System.out.println(joinPoint + " -> " + stateTransition);
    }

}

Code de test :

        System.out.println(AStateTransition.ACTIVATE.activate());
        System.out.println(AStateTransition.DEACTIVATE.deActivate());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X