The following is a UML state machine diagram for a hypothetical garage door opener. Keywords are shown in red, and state names are shown in blue.
The main states in the diagram are Closed and Open. Pressing a button causes the garage door to start opening (if it is closed) or to start closing (if it is open). Upon entry to Opening state, a signal is sent to the electronics to actually run the motor; the inverse happens upon entry to Closing state. There is a safety interlock: If the button is pressed when the door is closing, it reverses direction and opens again. There is also a second safety interlock: If the button is pressed to close the door, the closing will not commence if an obstruction is detected. There is also a light control; when the button is pressed to open the door, it turns on the light. When the safety interlock causes a closing door to reverse and open again, the light flashes before going on. The light turns off a minute after the door has finished opening.
The following is how you would program the above in Umple:
1 class Garage {
2 Boolean entranceClear;
3 GarageDoor {
4 Closed {
5 entry/{stopMotor();}
6 entry/{triggerEnergySaveMode();}
7 exit/ {triggerNormalEnergyMode();}
8 pressButton -> /{turnLightOn();} Opening;
9 }
10 Opening {
11 entry/{runMotorForward();}
12 openingCompleted -> Open;
13 }
14 Open {
15 entry/{stopMotor();}
16 do {wait(60000); turnLightOff();}
17 pressButton [getEntranceClear()] -> Closing;
18 }
19 Closing {
20 entry/{runMotorInReverse();}
21 closingCompleted -> Closed;
22 pressButton -> /{flashLightOn();} Opening;
23 }
24 }
25 }
Copy and past the above into UmpleOnline (removing the line numbers) and generate Java code to see what happens.
Here's an explanation of the code:
- Line 1: A state machine is defined in a class. There can be more than one per class.
- Line 2: This is an ordinary Umple (UML) attribute. See Tutorial 1 for a discussion of attributes. One thing to note is that this declaration will result in methods getEntranceClear() and setEntranceClear() in the API of class Garage. The former is called on Line 17.
- Line 3: A state machine called GarageDoor is being declared. In many respects a state machine functions as an attribute. The API getGarageDoor() is generated that returns an enum GarageDoor; the values of that enum will be each of the states.
- Lines 4, 10, 14 and 19: These are the states of the GarageDoor state machine. The first state listed (on Line 4) is the 'start state'. When an instance of the class Garage is first created, it will therefore be in Closed state.
- Lines 5, 6,. 11, 15 and 20: Upon entry into a state, these actions are to be performed. Arbitrary code can be placed in the parentheses. Such code will be passed through to the base language. Here we have used Java.
- Line 7: Upon exit from a state, this action is to be performed. Again, it is arbitrary code.
- Line 16: Whereas entry and exit code above is supposed to be 'instantaneous', i.e. to take no noticable computational time, the code specified in the 'do' block on this line can take an extended period. It therefore executed in a separately forked thread so as not to hold up the behaviour of the main state machine.
- Lines 8, 12, 17, 21 and 22: These represent the state transitions. In the diagram shown earlier, they are the five arcs between pairs of states. The destination state of the transition follows the ->. Each event name on a transition is generated as a method in the API. Even through there are 5 transitions, there are only three possible events, since the transitions from three separate states respond to this event.
- Lines 8 and 22: This shows a 'transition action'. This code is executed before transitioning to the new state.
- Line 17: This shows a 'guard'. A guard is a Boolean expression; the transition to Closing will only be taken if this evaluates to true. The guard expression tests the Boolean attribute declared on line 2.
- Write code somewhere else to call the event methods pressButton(), openingCompleted(), and closingCompleted().
- Write methods for each of the actions the state machine will call, such as stopMotor(), called in line 5 of the above Umple.
- Write methods that call setEntranceClear() to manipulate the EntranceClear attribute defined on line 2.
- Umple provides greater abstraction
- You will have to write many fewer lines of code. The above 25 lines of Umple translates to over 180 lines of Java.
- You are much less likely to make mistakes because error-prone code is generated for you.
- You can model in UML and have a one-to-one representation in Umple.
And you can go far beyond that. With Umple you can have in the same file as your state machine UML associations, ordinary Java methods and many other things. Furthermore, you can compose a state machine from many separate files using Umple's mixin mechanism.
One final point: The state machine diagram here is discussed further in my book. Object-Oriented Software Engineering: Practical Software Development Using UML and Java.