简体   繁体   中英

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");
     }       
}

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"); }

I'm not sure to have fully understand your question. Anyway, I'll suggest you to model active/passive state like a property in your class rather then use inheritance. Make your hierarchy something like:

public class BaseState {
     boolean active; //active or passive
}

public class WaitingState extends BaseState {

}

...

If you share common behaviour in your state machine you have two possibilities to implement that.

1) You can add the common implementation to the base state, so it can be called by any state implementation that inherits from the base state. The visibility of these methods would be protected .

2) A better solution in my oppinion is that you move the common behaviour into its own class that is not related to the states class hierarchy at all.
So you can think about a strategy class that implements the common behaviour and is referenced by the base class and can be called by any state.
The second solution is better because it increases the testability of both, the state machine and the strategy class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM