实施国家模式

时间:2013-08-07 12:13:04

标签: java locking state

我正在为我的应用程序在Java中实现一个状态模式,并且几乎不需要澄清。

状态机有状态1到状态5的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()是不合适的。

我的问题:  将accquireLock和releaseLock公开为Context类中的API并在每个状态类中使用它们是不错的java编程实践。

谢谢, 阿伦

1 个答案:

答案 0 :(得分:0)

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

关于在enter完成之前持有锁的声明,这正是锁定点:您不希望其他方法涉及或中断。相反,您应该开发某种事件队列来捕获所有事件,并在接收对象繁忙时等待分发它们。要么是这样,要么为你知道要中断的事件做一个特定的例外,这样你就可以在指定的事件被触发时绕过锁定。

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