Java 实现状态模式

Java 实现状态模式,java,locking,state-pattern,Java,Locking,State Pattern,我正在用Java为我的应用程序实现一个状态模式,需要做一些澄清 状态机有5个状态,从状态1到状态5。 共有5个事件(Event1到Event5)导致状态转换。 并非所有事件都适用于所有州。如果事件在该特定状态下不适用,应用程序将抛出异常 当状态机初始化时,它以state1开始 下面是接口和上下文类 /* Interface defining the possible events in each state. Each Implementer will handle event in a d

我正在用Java为我的应用程序实现一个状态模式,需要做一些澄清

状态机有5个状态,从状态1到状态5。 共有5个事件(Event1到Event5)导致状态转换。 并非所有事件都适用于所有州。如果事件在该特定状态下不适用,应用程序将抛出异常

当状态机初始化时,它以state1开始

下面是接口和上下文类

/*
 Interface defining the possible events in each state.
 Each Implementer will handle event in a different manner. 
*/
public interface State {
 /*
  Handlers for each event. Each Implementer will handle the vent in a different manner.
 */
 public void handleEvent1(StateContext context);
 public void handleEvent2(StateContext context);
 public void handleEvent3(StateContext context);
 public void handleEvent4(StateContext context);
 public void handleEvent5(StateContext context);
 // Method to enter state and do some action.
 public void enter(StateContext context);
 // Method to exit state and do some clean-up activity on exit .
 public void exit(StateContext context);
}

/*
  Context class which will handle the state change and delegate event to appropriate event handler of current state
*/
Class StateContext {

   private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

   private State currentState = null;

   StateContext() {
        currentState = new State1();
   }

   //Handle event1 and pass it to the appropriate event handler for the current state.
   public void handleEvent1() {
      currentState.handleEvent1(); 
   }
       .
       .
       .
   //Handle event5 and pass it to the appropriate event handler for the current state.
   public void handleEvent5() {
      currentState.handleEvent5(); 
   }

   // Method to change the state. 
   // This method will be called by each state when it needs to transit to a new state.
   public void changeState(State newState) {
          accquireLock();
          currentState.exit();
          currentState = newState;
          currentState.enter();           
   }

   // Release read lock and accquire write lock
   public void accquireLock() {
        lock.readLock().unlock()
        lock.writeLock().lock();
   }

   // accquire readlock and release write lock
   public void releaseLock() {
        lock.readLock().lock()
        lock.writeLock().unlock();
   }
}
为了简单起见,我只为一个状态提供了实现

public class State1 implements State {
       public void handleEvent1(StateContext context) {
          //Hand1e Event 1
       }
              .
              .
              .
      public void handleEvent5(StateContext context) {
          //Handle Event 5
       }


       public void enter(StateContext context) {
           //Release the lock here
           context.releaseLock();
           /*Here is my question. Is it a  good java practice to expose accquire and release lock in Context object. And use the exposed method here to release lock. 
           */

           // Do some action on entering the state. This may take few seconds to finish

       }  
}
我只想在进入状态后释放锁。我也不想在enter()完成之前一直持有锁。如果我将锁保持到enter完成,我将无法处理其他事件,它可能会超时。对于某些事件(不会真正改变状态),我们需要读取状态,并根据状态处理或忽略它们。如果我不释放锁,它们将无法处理。此外,在其他一些情况下,如果事件关闭(此事件会更改状态),则在enter()进行时状态机无法处理。我必须立即关闭状态机,因为在关闭事件发生后继续enter()是不合适的

我的问题: 将accquireLock和releaseLock公开为上下文类中的API并在每个状态类中使用,这是一种好的java编程实践

谢谢,
Arun

为了回答这个问题,如果锁由state“manager”类持有,那么该类应该是控制锁访问的类,而不是任何实际的state类

关于您关于将锁保持到
enter
完成的声明,这正是锁的要点:您不希望其他方法介入或中断。相反,您应该开发某种事件队列来捕获所有事件,并在接收对象忙时等待分发它们。或者为您知道将要中断的事件创建一个特定的异常,以便在触发指定事件时可以绕过锁


如果选择使用中断方法,则必须在每个
状态
类的
输入
方法中执行大量检查,以检查是否触发了关机事件。我认为它工作的唯一另一种方式是使每个
状态
扩展
线程
,这样您就可以随意中断/停止它,尽管在这种情况下这听起来不是一个有效的选项。

changeState()方法中执行代码后,为什么不调用
releaseLock()
?由于您是在该方法开始时获取锁的,因此在该方法结束时释放锁似乎是一致的设计,否?对于我的应用程序,如果我在enter()过程中收到关机事件以关闭机器,我不应该继续使用enter()。继续可能会造成不利影响,或者可能不会产生任何结果,除非在enter()完成之前浪费资源。在某些情况下,输入可能需要5分钟以上,并发送大量请求。如果我继续,请求可能无法到达接收者,或者接收者可能会放弃我的请求。在这种情况下,我应该立即停止并移动到初始状态(为此我需要锁定)。然后,您需要的是一种中断状态的
enter
方法,该方法超过您现有的任何锁定。将锁定对象视为状态更改的块,但关机事件优于任何状态更改事件,因此应该能够在任何时候生效。是。这似乎是一个不错的选择。将尝试适合我的应用程序。谢谢(2:)对不起,我没能说清楚。对于某些事件,我们必须读取状态并对其进行处理,或者相应地忽略它们。如果使用中断机制,则无法读取状态,因为写入锁由线程处理enter()持有。我已经编辑了这篇文章。我也同意你的观点,如果经理持有锁,只有他应该释放锁。在Manager中将获取和释放锁作为API公开,并在状态处理程序中获取和释放锁,这是一种好的做法。例如,在State1类中,事件处理程序类似于public void handleEvent1(){context.acquirelock();//Do something;context.releaseLock();}@Arun是的,这是一个很好的设计模式。另一种方法是在上下文的事件处理程序中而不是在状态中使用锁代码,但功能是相同的。好的,谢谢。。。然后,我的设计将在进入enter()方法后生成一个新线程来执行进入每个状态后需要执行的操作。通过这样做,在操作完成之前锁不会被保持,我可以处理只需要读取当前状态的事件。完成操作后,即在新生成的线程结束时,获取锁更改状态(如果需要)。