SDSU CS 635: Advanced Object-Oriented Design & Programming
Spring Semester, 1998
State

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98

Contents of Doc 19, State


State slide # 1
...Intent slide # 1
...Applicability slide # 1
...Example - SPOP slide # 2
......Outline of the State Pattern Implementation slide # 7
...Issue: Who defines the state transitions? slide # 10
...Issue: Sharing State Objects slide # 12
......Storing Instance Variables Elsewhere slide # 12
...Issue: Creating and Destroying State Objects slide # 14
...Consequences slide # 14



Doc 19, State Slide # 2

State

Intent

Allow an object to alter its behavior when its internal state changes. The object will appear to change it class.

State Pattern Structure

Applicability


Use the State pattern in either of the following cases:

An object's behavior depends on its state, and it must change its behavior at run-time depending on that state.

Operations have large, multipart conditional statements that depend on the object's state. Often, several operations will contain this same conditional structure.



Doc 19, State Slide # 3

Example - SPOP

Simple Post Office Protocol

SPOP is used to download e-mail from a server

SPOP supports the following command:


USER PASS Commands

USER with a username must come first
PASS with a password or QUIT must come after USER

If the username and password are valid, then the user can use other commands

LIST Command

Arguments: a message-number ( optional )

Returns: size of message in octets

If it contains an optional message number then returns the size of that message

Otherwise return size of all mail messages in the mail box


Doc 19, State Slide # 4
RETR Command

Arguments: a message-number

Returns: the mail message indicated by the number



QUIT Command

Arguments: none

Updates mail box to reflect transactions taken during the transaction state, then logs user out

If session ends by any method except the QUIT command, the updates are not done

SPOP Finite State Machine

Doc 19, State Slide # 5
Table Driven Representation

State-Command Table
USERPASSLISTRETRQUIT
Start     
HaveUserName     
Authorized     


Each state/command cell needs to contain:

Method to use when command occurs in that state
Next state on success of command
Next state on failure of command

Doc 19, State Slide # 6
The Switch Statement

class SPop
     {
     static final int QUIT = 1;
     static final int HAVE_USER_NAME = 2;
     static final int START = 3;
     static final int AUTHORIZED = 4;

     private int state = START;
     
     String userName;
     String password;
     
     public void user( String userName )
          {
          switch (state)
               {
               case START: 
                    {
                    this.userName = userName;
                    state = HAVE_USER_NAME;
                    break;
                    } 
               default:
                    {
                    // invalid command
                    sendErrorMessageOrWhatEver();
                    endLastSessionWithoutUpdate();
                    userName = null;
                    password = null;
                    state = START;
                    }
               }
          }

Doc 19, State Slide # 7
Implementation With Switch Statement Cont.

public void pass( String password )
          {
          switch (state)
               {
               case HAVE_USER_NAME: 
                    {
                    this.password = password;
                    if ( validateUser() )
                         state = AUTHORIZED;
                    else
                         {
                         sendErrorMessageOrWhatEver();
                         userName = null;
                         password = null;
                         state = START;
                         }
                    }
                    
               default:
                    {
                    // invalid command
                    sendErrorMessageOrWhatEver();
                    endLastSessionWithoutUpdate();
                    state = START;
                    }
               }
          }
     etc.     
     }

Doc 19, State Slide # 8

Outline of the State Pattern Implementation


SPOP State Classes

class SPop
     {
     private SPopState state = new Start();
          
     public void user( String userName )
          {
          state = state.user( userName );
          }

     public void pass( String password )
          {
          state = state.pass( password );
          }

     public void list( int messageNumber )
          {
          state = state.list( massageNumber );
          }

     etc.

Doc 19, State Slide # 9
SPopState

abstract class SPopState
     {
     public SPopState user( String userName )
          {
          put default action here 
          }

     public SPopState pass( String password )
          {
          put default action here 
          }

     public SPopState list( int massageNumber )
          {
          put default action here 
          }

     public SPopState retr( int massageNumber )
          {
          put default action here 
          }

     public SPopState quit(  )
          {
          put default action here 
          }
     }


Doc 19, State Slide # 10
class Start extends SPopState
     {
     public SPopState user( String userName )
          {
          return new HaveUserName( userName );
          }
     }
     
class HaveUserName extends SPopState
     {
     String userName;
     
     public HaveUserName( String userName )
          {
          this.userName = userName;
          }
          
     public SPopState pass( String password )
          {
          if ( validateUser( userName, password )
               return new Authorized( userName );
          else
               return new Start();
          }
     }


Doc 19, State Slide # 11

Issue: Who defines the state transitions?

The Context

class SPop
     {
     private SPopState state = new Start();
          
     public void user( String userName )
          {
          state.user( userName );
          state = new HaveUserName( userName );
          }

     public void pass( String password )
          {
          if ( state.pass( password ) )
               state = new Authorized( );
          else
               state = new Start();
          }

Doc 19, State Slide # 12
Issue: Who defines the state transitions?
The State


class SPop
     {
     private SPopState state = new Start();
     
     protected changeState( SPopState nextState )
          {
          state = nextState;
          }
          
     public void user( String userName )
          {state.user( userName, this ); }
     etc
     }

class Start extends SPopState
     {
     public SPopState user( String userName, SPop mailServer )
          {
          mailServer.changeState( HaveUserName( userName ) );
          }
     }

Note: Text places a changeState operation in SPopState, and subclasses call it

This is done because of C++ protect levels. The SPop changeState method should not be public

They make SPopState a friend of SPop
Doc 19, State Slide # 13

Issue: Sharing State Objects


Multiple contexts ( SPops) can use the same state object if the state object has no instance variables

A state object can have no instance variables if:

Storing Instance Variables Elsewhere

Variant 1


SPop stores them and passes them to states

class SPop
     {
     private SPopState state = new Start();
     
     String userName;
     String password;
          
     public void user( String newName )
          {
          this.userName = newName;
          state.user( newName );
          }

     public void pass( String password )
          {
          state.pass( userName , password );
          }
Doc 19, State Slide # 14
Storing Instance Variables Elsewhere
Variant 2

SPop stores them and states get data from SPop

class SPop
     {
     private SPopState state = new Start();
     
     String userName;
     String password;
          
     public String userName() { return userName; }

     public String password() { return password; }

     public void user( String newName )
          {
          this.userName = newName ;
          state.user( this );
          }

     etc.

class HaveUserName extends SPopState
     {
     public SPopState pass( SPop mailServer )
          {
          String useName = mailServer.userName();
          etc.
          }
     }

Doc 19, State Slide # 15

Issue: Creating and Destroying State Objects


Options:

1. Create state object when needed, destroy it when it is no longer needed

2. Create states once, never destroy them, use as needed (singleton)



Consequences


1. It localize state-specific behavior and partitions for different states

2. It makes state transitions explicit

3. State objects can be shared


visitors since 24-Mar-98