state based behavior ii
play

State-based Behavior II SWEN-261 Introduction to Software - PowerPoint PPT Presentation

State-based Behavior II SWEN-261 Introduction to Software Engineering Department of Software Engineering Rochester Institute of Technology There are a number of benefits for explicitly modeling state-based behavior. Explicitly defining


  1. State-based Behavior II SWEN-261 Introduction to Software Engineering Department of Software Engineering Rochester Institute of Technology

  2. 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 Today's discussion 2

  3. 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? • Balls thrown • Previous strike or spare • Pins knocked down • Previous frame score • Frame number  How many combinations are there? 3

  4. Here is what one Intro to SE team turned that approach into. if (pe.pinsDownOnThisThrow() >= 0) { if(curScore[i+1] != -1) { if (frameNumber == 9) { if (curScore[i+2] != -1){ if (pe.totalPinsDown() == 10) { if( curScore[i+2] != -2){ if(pe.getThrowNumber() == 1) { if( curScore[i+3] != -2){ if ((pe.totalPinsDown() != 10) && if ( i/2 > 0 ){ (pe.getThrowNumber() == 2 && if (curScore[i+3] != -1){ tenthFrameStrike == false)) { if( curScore[i+3] != -2){ if (pe.getThrowNumber() == 3) { if( i%2 == 0 && i < 18){ if (pe.pinsDownOnThisThrow() == 10) { if ( i/2 == 0 ) { } else if (pe.getThrowNumber() == 2) { if(curScore[i] != -2){ } else if (pe.getThrowNumber() == 3) { } else if (i/2 != 9){ if( i%2 == 1 && curScore[i - 1] + if(curScore[i] != -2){ curScore[i] == 10 && } else if (i < 18){ i < current - 1 && i < 19){ if(curScore[i] != -1 && i > 2){ if (i > 1) { if(curScore[i] != -2){ } else if( i < current && i%2 == 0 && if (i/2 == 9){ curScore[i] == 10 && i < 18){ if (i == 18){ if (curScore[i+2] != -1) { if(curScore[i] != -2){ if(curScore[i+3] != -1) { } else if (i/2 == 10) { } else if(curScore[i+4] != -1) { if(curScore[i] != -2){ if (strikeballs == 2){ 38 if statements in a file of 621 lines of code. 4

  5. 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. … 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 5

  6. 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. Today's discussion 6

  7. You need to decide how you will implement the core aspects of a state machine.  States  Transitions • State attribute in class • Setting state attribute • Separate class for each • Transition class state  Guards  Events • If statement tests • Calling a method • Explicit guard methods • Event dispatch  Actions • Interrupt • Statement execution • Time out • Explicit action methods • End of an activity. Simplest approach for switch-based implementation. 7

  8. 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

  9. 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

  10. 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

  11. 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

  12. With the state-based implementation the states are explicitly coded. public synchronized boolean makeGuess( final int myGuess) { boolean validGuess = false ; This state machine has only one event — a call to makeGuess(). switch (currentState) { case WAIT_FOR_GUESS : if (myGuess >= 0 && myGuess < UPPER_BOUND ){ howManyGuessesLeft--; You need to implement code for each state where this event triggers a transition. if (myGuess == numberToGuess) { currentState = State. GAME_WON ; } You typically implement guards as else if (howManyGuessesLeft <= 0) { the conditional of an if statement. currentState = State. GAME_LOST ; } The transition is completed by setting validGuess = true ; the current state to the next state. } break ; // Guesses are expected only when the game is in WAIT_FOR_GUESS. default : throw new IllegalStateException("No more guesses allowed."); What you do if the event is received when you } return validGuess; do not expect it, is application dependent. } 12

  13. 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

Recommend


More recommend