Search code examples
javaoopinheritancefsm

Finite State Machine design problem on Java


I want to implement FSM like below

  • First Level Most basic State is BASE_STATE. All states derive from BASE_STATE.
  • Second Level, WAITING_STATE, RUNNING_STATE, END_STATE, ... so on (Derived from BASE_STATE. No new functionality)
  • Third level, There are 2 groups states (ACTIVE and PASSIVE), One-on-one matching for all second level states like

ACTIVE_WAITING_STATE , ACTIVE_RUNNING_STATE , ACTIVE_END_STATE, so on PASSIVE_WAITING_STATE, PASSIVE_RUNNING_STATE, PASSIVE_END_STATE, so on

most functionalities are common for ACTIVE and PASSIVE states, just some small functions overrided. There is no problem until here. Problem is, All third level group have common functions. I mean, For example I have to implement 2 different increment() function one of is ACTIVE_xxx_STATEs, another one is PASSIVE_xxx_STATEs. How to do this without re-written for all states (eg. ACTIVE_WAITING_STATE , ACTIVE_RUNNING_STATE , ACTIVE_END_STATE, and also PASSIVE states)

To clearify my questions, my ugly sol'n. Problem is increment functions is same and re-written for all ActivexxxState (and also PassiveXXXState).

public class BaseState {
    // Lots of functions
}

public class WaitingState extends BaseState{
    // Lots of functions
}

public class RunningState extends BaseState{
    // Lots of functions
}

public class EndState extends BaseState{
    // Lots of functions
}

public Class ActiveWaitingState extends WaitingState {
     // Few unique functions
     private void increment() {
         System.out.println("increment active");
     }       
}


public Class ActiveRunningState extends RunningState {
     // Few unique functions
     private void increment() {
         System.out.println("increment active");
     }       
}

public Class ActiveEndState extends EndState {
     // Few unique functions
     private void increment() {
         System.out.println("increment active");
     }       
}

public Class PassiveWaitingState extends WaitingState {
     // Few unique functions        
     private void increment() {
         System.out.println("increment passive");
     }       
}

public Class PassiveRunningState extends RunningState {

     private void increment() {
         System.out.println("increment passive");
     }       
}

public Class PassiveEndState extends EndState {

     private void increment() {
         System.out.println("increment passive");
     }       
}

Solution

  • I would make increment() a protected method in BaseState so it is implemented once.


    I have written an article on using enums to build a state machine. This can avoid the need to create classes everywhere for each state and still support some inheritance.


    In answer to your comment.

    abstract class BaseState {
       public abstract boolean isPassive();
       public boolean increment() {
          System.out.println("increment "+(isPassize() ? "passive" : "active");
       }
    }
    
    class PassiveState {
       public boolean isPassive() { return true; }
    }
    

    If you don't want to have multiple isPassive methods you could assume a class naming convention

    public boolean isPassive() { return getClass().getSimpleName().startsWith("Passive"); }