2013-08-07 118 views
2

我正在为我的应用程序实现Java中的状态模式,并且需要很少的说明。实现状态模式

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

当状态机得到初始化时,它从状态1开始。

以下是接口和上下文类。

/* 
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()正在进行时,状态机将无法处理它。我必须立即关闭状态机,因为在关机事件发生后继续输入()不适合。

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

感谢, 阿伦

+0

为什么在代码在你的'changeState()'方法中执行后你不调用'releaseLock()'?既然你在该方法开始时获得了锁,那么在它的最后释放锁似乎是一致的设计,不是吗? – Deactivator2

+0

对于我的应用程序,如果我在enter()进行时收到关闭机器的关机事件,我不应该继续输入()。继续可能会导致不利影响,或者可能不会导致任何结果,除非浪费资源直到enter()结束。在某些情况下,输入可能需要超过5分钟,并发送很多请求。如果我继续请求,可能无法到达接收方,或者接收方可能会丢弃我的请求,我应该立即停止并转到初始状态(为此我需要锁定)。 – Arun

+0

然后,你需要的是一种中断状态的'enter'方法的方法,它超越了你已有的任何锁定。将锁对象视为状态更改的块,但关闭事件优于任何状态更改事件,因此应该能够随时生效。 – Deactivator2

回答

0

要回答这个问题,如果锁是国家“经理”班举行,那么该类应该在一个控制访问锁定,没有任何实际状态类的。

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

如果您选择使用中断方法,则需要在每个State类的enter方法中执行多次检查,以检查是否触发了关闭事件。我看到它唯一的工作方式是让每个State扩展Thread,以便您可以随意中断/停止,尽管在这种情况下听起来不是一个有效的选项。

+0

我同意你的观点,如果经理拿着锁,只有他应该释放锁。将获取和释放锁暴露为管理器中的API并在状态处理程序中获取并释放它是一种很好的做法。例如在State1类中,事件处理程序就像public void handleEvent1(){context.accquireLock(); //做一点事; context.releaseLock(); } – Arun

+0

@Arun是的,这是一个很好的设计模式。另一种方法是将锁码置于上下文的事件处理程序中,而不是状态,但功能相同。 – Deactivator2

+1

好的谢谢...那么我的设计是在进入enter()方法之后产生一个新的线程来执行进入每个状态后需要完成的操作。通过这样做,锁定将不会被保留,直到操作完成,我可以处理需要只读取当前状态的事件。在完成操作之后,即在新产生的线程结束时获取锁定改变状态(如果需要的话)。 – Arun