22

I have a problem at hand and I am not getting which design pattern to use. The problem goes as such:

I have to build a system which has 'N' states and my system has to do a transition from any state to any other state depending on some conditions. Ex: On condition 1, movement from State 1 to 3 and on condition 2 from state 1 to 4.

Even the transition from one state to other state can be done on 2 or more different conditions.

For example, transition from State 1 to state 3 can be done when:
condition 1 : "Its a Sunday"
condition 2: "Its Raining"
condition 3: "Its Raining and Sunday"
In each condition, the processing at State 3 can be different.

I hope I was able to understand the problem legibly. Kindly help.

Thanks a lot

Anurag
  • 140,337
  • 36
  • 221
  • 257
Amit
  • 435
  • 2
  • 8
  • 16
  • 1
    I believe the problem could be simplified by splitting the states into more states, one for each way of processing (i.e. if condition 1 for doing a transition from 1 to 3 results in processing state 3 in a different way from condition 2, then split state 3 into two different states. – Buhb Jan 13 '10 at 15:31
  • state-machine related: http://stackoverflow.com/questions/1647631/c-state-machine-design – jldupont Jan 13 '10 at 19:59
  • Petri nets can handle this kind of thing. – reinierpost Oct 26 '12 at 10:55

6 Answers6

42

Its clearly a case of a finite-state-machine but its better to combine the conditions rather than create a new condition for each combination. I didn't like the Java example for State pattern on Wikipedia as states know about other states which wouldn't make sense in a lot of scenarios. A transition table that keeps a track of the from state, applicable condition(s), and to state, helps take care of that problem.

My two cents for an object oriented-finite-state-machine. There are improvements you could do on the OO front, but it gets the idea across.

class Transition {
    State from;
    Set<Condition> conditions;
    State to;
}

class State {
    String state;
}

class Condition {
    String condition;
}

The state machine can be constructed with the above types. There is no error checking, but you could throw an exception or something if no next state is found for some conditions.

class StateMachine {
    List<Transition> transitions;
    State current;

    StateMachine(State start, List<Transition> transitions) {
        this.current = start;
        this.transitions = transitions;
    }

    void apply(Set<Condition> conditions) {
        current = getNextState(conditions);
    }

    State getNextState(Set<Condition> conditions) {
        for(Transition transition : transitions) {
            boolean currentStateMatches = transition.from.equals(current);
            boolean conditionsMatch = transition.conditions.equals(conditions);
            if(currentStateMatches && conditionsMatch) {
                return transition.to;
            }
        }
        return null;
    }
}

And a test run:

Edit: With some more transitions and new states based on your comment:

State one = new State("one");
State two = new State("two");
State three = new State("three");

Condition sunday = new Condition("Sunday");
Condition raining = new Condition("Raining");
Condition notSunday = new Condition("Not Sunday");
Condition notRaining = new Condition("Not Raining");

List<Transition> transitions = new ArrayList<Transition>();
transitions.add(one, new Set(sunday), three);
transitions.add(one, new Set(sunday), two); // <<--- Invalid, cant go to two and three
transitions.add(one, new Set(raining), three);
transitions.add(one, new Set(sunday, raining), three);
transitions.add(one, new Set(notSunday, notRaining), three);

StateMachine machine = new StateMachine(one, transitions);
System.out.print(machine.current); // "one"
machine.apply(new Set(sunday, raining));
System.out.print(machine.current); // "three

I had a bitter experience with using a state machine for a fairly large project. The problem was with composite states. Just like the composite condition you mentioned (sunday and raining), there could technically be composite states which could further be broken down into unit states. This may or may not be the case in your situation, but still worth mentioning. If that is the case, it's best to modify the classical finite state machine and use a set of states instead of a single state to represent the from and to states. If your N is large, this will help keep sanity levels intact. Think hotmail folders vs gmail tags. The transition table would then be presented as

Transition(Set<State> from, Set<Condition> conditions, Set<State> to)
Anurag
  • 140,337
  • 36
  • 221
  • 257
  • Thanks a lot :) Its exactly solving my purpose. Can you pls elaborate a bit on "setting the conditions" part and processing it further. So suppose my condition is like "if sunday = y then goto State S2 from S1 or to state S3 if sunday=n and raining=n and to state S3 if raining=y". The conditions and states are criss-crossing at multiple points. Thanks a lot. – Amit Jan 15 '10 at 09:29
  • 1
    You'd have to break the transitions down into the `from` state, and the set of `conditions` that when applied to this `state`, lead to the `to` state. Also this has to be deterministic. So there cannot be two states where the `from` state and `conditions` are alike, but the `to` state is different as the state machine would not know which one to pick. It's a bug in my code as it will always pick the first match, but that will be an invalid state machine. – Anurag Jan 15 '10 at 18:27
  • Maybe you need to return `this.current` instead of `null` in `getNextState` to not get an error when there are no appropriate transitions. No changing state is better than crash. – TigerTV.ru Jan 15 '20 at 03:04
14

This sounds like the typical use for a finite state machine

in short, the state machine describes the various states in which your system can be, and under which conditions it can go from state to state. A state machine is described exactly as your English description. And it can be formally described using state diagrams

in code you could make a state machine like this:

 enum State { Init, ShowMenu, ShowMsg, DisplayVideo, Exit };
 State state = State.Init;

 while (state != State.Exit)
 {
      switch(state)
      {
           case State.Init:
                init();
                state = State.ShowMenu;
                break;
           case State.ShowMenu:
                if(lastMenuItemSelected==1) state = State.ShowMsg;
                if(lastMenuItemSelected==2) state = State.DisplayVideo;
                break;
           case State.ShowMsg:
                ....
                break;
           ....
 }

I'm not sure if I got the exact syntax correct for Java...I'm more into C#

Toad
  • 15,593
  • 16
  • 82
  • 128
  • if I had upvotes left (quota reached for the day), you would get a +1. – jldupont Jan 13 '10 at 15:26
  • 3
    explaning my downvote - from object-oriented point of view using if/switch is not preferred. The State pettern is the more object-oriented way of handling states. – Bozho Jan 13 '10 at 16:03
  • 1
    I clearly say: you "could" make a statemachine like this. I think my example is much easier to grasp than the wiki explanation of the state pattern – Toad Jan 13 '10 at 18:32
  • it is easier to grasp but that doesn't make it more appropriate :) – Bozho Jan 13 '10 at 18:47
  • 3
    @Bozho There is no good reason for something to be "purely" object oriented, or "purely" functional etc. Certain problem sets are better and more coherently solved using different or mixed paradigms. I would argue that if the example is easier to grasp, that is a VERY GOOD REASON to do something in that way. Saying it's bad "because it's not OO" is a fallacious argument. Why is something not being "OO" bad? Easy to grasp => easy to maintain => quicker to fix => faster and more reliable product releases. – Vincent McNabb Jun 08 '15 at 22:08
  • @Bozho I would say an OO state machine is very good in complex situations where there are complex states. But with 3-4 states, it can be overkill to do something other than a switch case. – Vincent McNabb Jun 08 '15 at 22:10
9

won't the state pattern do the work?

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
Benny
  • 8,547
  • 9
  • 60
  • 93
2

As others have said a state machine can be modelled in procedureal code with a switch or in OO code with the state pattern, which is probably what you were after.

However a 3rd way is to actually code it as a graph, with states as nodes and conditions as directed edges. The visitor pattern can then be used to apply the graph to different uses. this would lend itself particularly well to designs where the states and/or the transitions could be user defined, but would probably be more memory intensive then the hard coded state machines described in the other answers.

jk.
  • 13,817
  • 5
  • 37
  • 50
1

State design pattern works on the concept of state change. Entire process life-cycle can be divided in multiple phases.With completion of each phase process exits from one state and enters in to another state.

For example In JSF framework entire web request response lifecycle is divided in six phases:

After completion of every phase process exits from a state and enters into another state. For example after RestoreValuePhase we can say ViewRestored as exit state and RequestApply as entering state .

So to implement State design pattern It is required to divide entire process in such a way that It can be processed in multiple phases with every phase exit defining a state change.

Now let's understand this with below code.

Any project lifecycle can be divided in multiple phases like

requirementAssessment
Design
Development
QualityAssessment
Deploy
Closure

So these are the phases used in below example

Rules :

  1. We need to define a class where we can store the current state of the process. NextPhase class in below code is doing that.

  2. We need to define an Interface wherein we can provide the contact method that would be implemented in each phase.In below code ProjectPhase is doing that.

Learn more about State design pattern here -- State Design Pattern

http://efectivejava.blogspot.in/2013/09/java-state-design-patten-oops-state.html?utm_source=BP_recent

manoj
  • 11
  • 1
1

The first thing I noticed about your example was that State 3 = (State 1 == true && State 2 == true). This will not scale very well as more possible states become involved. If you are only considering whether it is raining or whether it is Sunday, you can have an enumeration like this, with 4 possible types:

enum State { CLEAR_OTHER_DAY, RAINING_OTHER_DAY, CLEAR_SUNDAY, RAINING_SUNDAY }

This would allow you to state conditions cleanly in a switch block when it is time to code. But if you have to also consider whether it is warm outside, you have to add 4 more values to that enum to capture all possible conditions. And later in your project, your code may need to capture more conditions than you currently envision.

As for a design pattern, the State pattern and its Java example on Wikipedia look like a good place to start.

Wikipedia's example has a StateContext class with a method called setState that takes in a name. I thought about suggesting that you add the state determination logic here, but that would make your StateContext class need to get too close to the implementation details of your other classes. It would be better to put a method for determining the system's state in a class that would easily know the conditions for going from one state to another. This way, if your project needs to change in the future and you either have more states to keep track of or different conditions, you only need to maintain the logic in one place.

David
  • 1,187
  • 1
  • 10
  • 22