state-based behavior ii

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

Upload: others

Post on 17-Apr-2022

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: State-based Behavior II

SWEN-261 Introduction to Software Engineering

Department of Software Engineering Rochester Institute of Technology

State-based Behavior II

Page 2: 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

Page 3: State-based Behavior II

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

Page 4: State-based Behavior II

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.

Page 5: State-based Behavior II

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

Page 6: State-based Behavior II

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

Page 7: State-based Behavior II

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.

Page 8: State-based Behavior II

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

Page 9: State-based Behavior II

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

Page 10: State-based Behavior II

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

Page 11: State-based Behavior II

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

Page 12: State-based Behavior II

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.

Page 13: State-based Behavior II

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