state-based behavior ii
Post on 17-Apr-2022
1 Views
Preview:
TRANSCRIPT
SWEN-261 Introduction to Software Engineering
Department of Software Engineering Rochester Institute of Technology
State-based Behavior II
There are a number of benefits for explicitly modeling state-based behavior.
Explicitly defining this state-based behavior
provides a common specification for the team.
Allowing the state behavior to evolve implicitly
creates a situation where every team member
may have a different model of the behavior.
You can model state-based behavior in many
areas of your software system. • Web application interface
• User interface
• Individual class-behavior
2
Today's discussion
With class behavior modeled, you may decide to have the states be implicit in the implementation.
Allow the state definition to implicitly evolve • Standard approach as behavior develops
• Maintain information in a collection of attributes
• State is defined as logical combinations of values
Consider that you are implementing scoring for
bowling. What information do you need to use?
How many combinations are there?
3
• Balls thrown
• Pins knocked down
• Frame number
• Previous strike or spare
• Previous frame score
Here is what one Intro to SE team turned that approach into.
if (pe.pinsDownOnThisThrow() >= 0) {
if (frameNumber == 9) {
if (pe.totalPinsDown() == 10) {
if(pe.getThrowNumber() == 1) {
if ((pe.totalPinsDown() != 10) &&
(pe.getThrowNumber() == 2 &&
tenthFrameStrike == false)) {
if (pe.getThrowNumber() == 3) {
if (pe.pinsDownOnThisThrow() == 10) {
} else if (pe.getThrowNumber() == 2) {
} else if (pe.getThrowNumber() == 3) {
if( i%2 == 1 && curScore[i - 1] +
curScore[i] == 10 &&
i < current - 1 && i < 19){
if (i > 1) {
} else if( i < current && i%2 == 0 &&
curScore[i] == 10 && i < 18){
if (curScore[i+2] != -1) {
if(curScore[i+3] != -1) {
} else if(curScore[i+4] != -1) {
if (strikeballs == 2){
if(curScore[i+1] != -1) {
if (curScore[i+2] != -1){
if( curScore[i+2] != -2){
if( curScore[i+3] != -2){
if ( i/2 > 0 ){
if (curScore[i+3] != -1){
if( curScore[i+3] != -2){
if( i%2 == 0 && i < 18){
if ( i/2 == 0 ) {
if(curScore[i] != -2){
} else if (i/2 != 9){
if(curScore[i] != -2){
} else if (i < 18){
if(curScore[i] != -1 && i > 2){
if(curScore[i] != -2){
if (i/2 == 9){
if (i == 18){
if(curScore[i] != -2){
} else if (i/2 == 10) {
if(curScore[i] != -2){
4
38 if statements in a file of 621 lines of code.
You should not be afraid to implement state-based behavior using explicit states.
It may seem more complex but in the end it often is • Easier to implement
• Easier to expand
• Easier to understand
• Easier to maintain
Alan Skorkin gives the following reason for
developers not using states explicitly.
5
… early on you don't feel like your objects' state machine behaviour is complex
enough to warrant a "full-blown" state machine (YAGNI and all that jazz), but
later on – when it IS complex enough – you feel like you've invested too much
time/effort to replace it with something that has equivalent functionality. It's a bit
of a catch-22. It's overkill and by the time it's not, it's too late.
Alan Skorkin
Why Developers Never Use State Machines
Explicitly using states in the implementation provides an easier model to code translation.
There are multiple approaches that you can use for
an implementation with explicit states. • Switch-based implementation
• State-transition table (2 dimensions: states x events)
• State design pattern
These are discussed in the book chapter listed in
the resources for this lesson.
6
Today's discussion
You need to decide how you will implement the core aspects of a state machine.
States • State attribute in class
• Separate class for each
state
Events • Calling a method
• Event dispatch
• Interrupt
• Time out
• End of an activity.
Transitions • Setting state attribute
• Transition class
Guards • If statement tests
• Explicit guard methods
Actions • Statement execution
• Explicit action methods
7
Simplest approach for switch-based implementation.
Here are the mechanics for the simplest to understand switch-based implementation.
Use an enum to define the states. • Current state is stored in a class attribute.
• Transition to a new state by changing current state.
Every method on the interface will be implemented with a switch on the current state.
Events will be method calls.
Guards will be if statement conditions.
Actions will be statements executed in the event
method.
Use private helper methods as needed.
8
We will go back and consider the state-based behavior of the Guessing Game sample webapp.
What states does a GuessGame object have? • There is more than one possible set of states.
Here is one possible statechart for its behavior.
9
In the original implementation, the states are encoded implicitly in combinations of attributes.
The game is lost public synchronized boolean hasMoreGuesses() {
return howManyGuessesLeft > 0;
}
The game is won – detected as return value from makeGuess() return myGuess == numberToGuess;
Waiting for another guess public synchronized boolean hasMoreGuesses() {
return howManyGuessesLeft > 0;
}
10
You start with a definition of the states and an attribute to hold the current state.
/**
* States for the game in a state-based implementation.
*/
private enum State {WAIT_FOR_GUESS, GAME_WON, GAME_LOST}
/**
* The current state the object is in.
*/
private State currentState = State.WAIT_FOR_GUESS;
11
With the state-based implementation the states are explicitly coded.
public synchronized boolean makeGuess(final int myGuess) {
boolean validGuess = false;
switch (currentState) {
case WAIT_FOR_GUESS:
if (myGuess >= 0 && myGuess < UPPER_BOUND){
howManyGuessesLeft--;
if (myGuess == numberToGuess) {
currentState = State.GAME_WON;
}
else if (howManyGuessesLeft <= 0) {
currentState = State.GAME_LOST;
}
validGuess = true;
}
break;
// Guesses are expected only when the game is in WAIT_FOR_GUESS.
default:
throw new IllegalStateException("No more guesses allowed.");
}
return validGuess;
} 12
This state machine has only one
event—a call to makeGuess().
You need to implement code for each state
where this event triggers a transition.
What you do if the event is received when you
do not expect it, is application dependent.
You typically implement guards as
the conditional of an if statement.
The transition is completed by setting
the current state to the next state.
For objects with complex behavior, a state machine is often the only design that is maintainable.
Add state machines to your toolbox for defining
software behavior • Even without implementing the states explicitly, you
gain by having a clear definition of the behavior
For more complex systems, implementation
techniques other than switch-based are better. • State design pattern separates concerns for each
state into a separate class
• State-machine frameworks provide polymorphic
design of state machine
• Dispatch mechanism sends events through system
• Tools provide auto-coding of state machine
operation directly from the statechart definition
13
top related