3

I am implementing a state pattern in Java for my application and need few clarifications.

The state machine has 5 states State 1 to State 5. The are a total of 5 events(Event1 to Event5) which causes the state transition. Not all events are applicable in all the states. If the event is not applicable in that particular state the application will throw exception.

When the state machine gets initialized it starts with state1.

Following is the interface and the context class.

/*
 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();
   }
}

To make it simple, I have provided implementation for only one state.

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

       }  
}

I want to release the lock only after entering state. Also I don't want to hold the lock till enter() finishes. If I hold the lock till enter finishes I cannot handle other events and it may get timed-out.For some events (which don't really change the state) we need to read the state and based on the state we can process them or ignore them. If I don't release lock they cannot be processed.Also in some other cases if an event comes to shutdown(this event changes the state) the state machine while enter() is in progress I cannot handle it. I have to shutdown the state machine immediately since it is not appropriate in continuing the enter() after shutdown event has come.

My Question: Is it good java programming practice to expose the accquireLock and releaseLock as an API in Context class and use them in each state class.

Thanks, Arun

4

1 回答 1

0

要回答这个问题,如果锁由状态“管理器”类持有,那么该类应该是控制锁访问的类,而不是任何实际的状态类。

关于您关于持有锁直到enter完成的声明,这正是锁的重点:您不希望其他方法参与或中断。相反,您应该开发某种事件队列来捕获所有事件,并在接收对象忙时等待分发它们。要么,要么为您知道将要中断的任何事件设置一个特定的例外,以便您可以在触发指定的事件时绕过锁。

如果您选择使用中断方法,您将不得不在每个State类的enter方法中实现一些检查,以检查是否触发了关闭事件。我认为它工作的唯一另一种方法是使每个State扩展Thread,以便您可以随意中断/停止它,尽管在这种情况下这听起来不是一个有效的选项。

于 2013-08-07T12:49:57.297 回答