如何在 JPA 域模型中实现状态设计模式

发布于 2024-09-28 20:16:49 字数 1456 浏览 1 评论 0原文

我想在 JPA 中实现状态设计模式。我目前这样做的方式在这个 博客中概述发布

作者使用包含所有可用状态实现的枚举,而不是创建抽象类/接口来进行状态抽象并为每个状态编写实现。我发现这种方法非常有用,因为枚举可以在 JPA 中轻松序列化,并且您可以存储对象的当前状态,而无需额外的工作。我还将状态接口和所有状态类嵌套到枚举中,使它们成为私有的,因为它们是特定于实现的并且不应该对任何客户端可见。这是枚举的代码示例:

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);
    }
  }
}

我想与您分享并了解您的想法。你觉得这有用吗?您将如何在 JPA 域模型中实现状态设计模式?

I want to implement the state design pattern in JPA. The way I am currently doing this is outlined in this blog post.

The author uses an enum containing all available state implementations instead of creating abstract class/interface for state abstraction and writing implementation for each state. I find this approach very useful, since enums can be easily serialized in JPA and you can store the current state of your object without additional effort. I also nested the state interface and all state classes into the enum making them private, since they are implementation specific and should not be visible to any client. Here's a code example of the 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);
    }
  }
}

I'd like to and share this with you and get your thoughts on it. Do you find this useful? How would you implement the state design pattern in a JPA domain model?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷情妓 2024-10-05 20:16:50

作为推论,这种 AspectJ 模式与特定于常量的 Enum 类相结合也是有用的。我在这里不展示 Spring 集成,因为这仅关注 AspectJ。但我想我们也可以将 Spring 与 AspectJ 一起使用。

还有一点是,面向对象模式对于这个用例来说非常强大。我展示此模式只是因为问题指向博客文章,其中包含 Spring 和 AspectJ 示例的链接。

我还需要在 JPA 中使用良好的 OO 模式。

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);
    }

}

测试代码:

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

As a corollary this AspectJ pattern combined with constant-specific Enum classes is also useful. I am not showing Spring integration here as this focuses only on AspectJ. But I guess we can use Spring with AspectJ too.

One more point is that OO patterns can be powerful for this usecase. I show this pattern only because the question points to the blog post which has a link to a Spring and AspectJ example.

And I also have a need to use good OO patterns with 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);
    }

}

Test code :

        System.out.println(AStateTransition.ACTIVATE.activate());
        System.out.println(AStateTransition.DEACTIVATE.deActivate());
韶华倾负 2024-10-05 20:16:49

嗯,这是一个老问题,但是为了那些可能搜索档案的人 - 我使用了带有枚举(而不是字符串)的 spring 状态机。

关于处理转换,有一些注释允许在转换发生时调用您的函数。

1.1.0.RELEASE 提供了一种默认机制,通过 持久化 StateMachineContext,以及使用 坚持配方

现在参考 JPA - 可以让实体监听器在 postload< 上初始化状态机/a> (@Postload),我认为这不是一条好路。

Well it's an old question, but for the sake of those who might search archives - I have used spring state machine with enums (instead Strings).

Regarding handling transitions, there are annotations that allow your functions to be called when transition happens.

1.1.0.RELEASE gives a default mechanism to persist a state by persisting StateMachineContext, and an alternative using persist recipe.

Now refering to JPA - it's possible to have Entity Listener that will initialize statemachine on postload (@Postload), I think it's not good path to go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文