1
\$\begingroup\$

During development I needed to design a state machine with decision which runs to completion and performs state transition without the need to wait for events. So i come up with the following implementation that I want to share.

So the state machine is described with the following Enum

public enum PnoBarringState {
  OPERATOR_WHITE_LIST_START {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        if (commonMethods.isMatchingOperatorsWhiteList(sessionData, pnoValue)) {
            return GROUP_WHITE_LIST;
        } else {
            return OPERATOR_BLACK_LIST;
        }
    }
  },
  GROUP_WHITE_LIST {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        if (commonMethods.isMatchingGroupsWhiteList(sessionData, pnoValue)) {
            return PNO_CHECK_FINISHED;
        } else {
            return GROUP_BLACK_LIST;
        }
    }
  },
  OPERATOR_BLACK_LIST {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        if (commonMethods.isMatchingOperatorsBlackList(sessionData, pnoValue)) {
            return PNO_FORBIDDEN_NUMBER_OPERATOR_LEVEL;
        } else {
            return GROUP_WHITE_LIST;
        }
    }
  },
  GROUP_BLACK_LIST {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        if (commonMethods.isMatchingGroupsBlackList(sessionData, pnoValue))
            return PNO_FORBIDDEN_NUMBER_GROUP_LEVEL;
        else {
            return PNO_CHECK_FINISHED;
        }
    }
  },
  PNO_CHECK_FINISHED {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        return this;
    }

    @Override
    public boolean hasNext() {
        return false;
    }
  },
  PNO_FORBIDDEN_NUMBER_OPERATOR_LEVEL {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        throw new CustomUncheckedException( "Operator Level Barring");
    }
  },
  PNO_FORBIDDEN_NUMBER_GROUP_LEVEL {
    @Override
    public PnoBarringState nextState(SessionData sessionData, String pnoValue) {
        throw new CustomUncheckedException("Group Level Barring");
    }
  };

  public abstract PnoBarringState nextState(SessionData sessionData, String pnoValue);

  public boolean hasNext() { return true; }
}

Function "nextState()" is abstract and implemented in each state in order to examine the transition and return to a new state. Only the "END" state is returning to the same state. Since it is also desinged to be used in a run-to-completation a "hasNext()" function is provided. The "END" state is overwritting so as to declare the finish of the state-machine.

This enum is then used inside a normal application code with the following way.

PnoBarringState pnoBarringState = PnoBarringState.OPERATOR_WHITE_LIST_START;

while (pnoBarringState.hasNext()) {
    pnoBarringState = pnoBarringState.nextState(sessionData, pnoValue);
}

I am not sure whether any pattern describes it in the same way but i was feeling like sharing it. Any other approaches are considered valuable.

\$\endgroup\$
15
  • 4
    \$\begingroup\$ There are way better OO design-patterns than this. Use Flyweights instead of the enum. \$\endgroup\$ – πάντα ῥεῖ Aug 6 '20 at 17:57
  • \$\begingroup\$ To be honest I don't get how with Flyweights will create a run-to-completion case. I mean an single event trigger will cause the pass from all affected states. Are you also referring that the states will be Different Concrete classes (which is somethign i am trying to avoid)? \$\endgroup\$ – Makis Papapanagiotou Aug 7 '20 at 5:43
  • \$\begingroup\$ "which is somethign i am trying to avoid" Why so? Usually you should avoid to clutter the context with the concrete states, and especially with their specific behaviors. \$\endgroup\$ – πάντα ῥεῖ Aug 7 '20 at 6:04
  • \$\begingroup\$ At least i am trying to avoid to depict every state with a class. State Pattern for example creates too many useless classes. Anyway ... Do you have any small sampe how Flyweights migth help to create a "state or transition pattern since I have never seen any implementation for such a thing. \$\endgroup\$ – Makis Papapanagiotou Aug 7 '20 at 6:37
  • \$\begingroup\$ Please explain why you feel that the classes created in the state-pattern are useless. \$\endgroup\$ – TorbenPutkonen Aug 7 '20 at 6:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.