SDSU CS 696: Advanced OO
Spring Semester, 1997
Doc 13, State and Strategy

To Lecture Notes Index
San Diego State University -- This page last updated Apr 3, 1997
----------

Contents of Doc 13, State and Strategy


State slide # 1
...Intent slide # 1
...Applicability slide # 1
...Consequences slide # 1
...Implementation slide # 2
...Example - SPOP slide # 3
......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
Strategy slide # 15
...Intent slide # 15
...Example: STL Container Adaptors slide # 15
...Applicability slide # 18
...Consequences slide # 18
...Implementation slide # 19


Doc 13, State and Strategy Slide # 1

State

Intent

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

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.

Consequences


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

2. It makes state transitions explicit

3. State objects can be shared



Doc 13, State and Strategy Slide # 2

Implementation


1. Who defines the state transitions

2. A table-based alternative

3. Creating and destroying State object.

4. Using dynamic inheritance


Doc 13, State and Strategy 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 13, State and Strategy 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


Doc 13, State and Strategy Slide # 5
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 13, State and Strategy Slide # 6
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 13, State and Strategy Slide # 7

Outline of the State Pattern Implementation




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 13, State and Strategy Slide # 8
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 13, State and Strategy Slide # 9
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 13, State and Strategy Slide # 10

Issue: Who defines the state transitions?


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 13, State and Strategy Slide # 11
Issue: Who defines the state transitions?

A Second Way
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 13, State and Strategy Slide # 12

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 13, State and Strategy Slide # 13
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 13, State and Strategy Slide # 14

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


Doc 13, State and Strategy Slide # 15

Strategy


Intent

Define a family of algorithms, encapsulate each one, and make them interchangeable

Strategy lets the algorithm vary independently from clients that use it

Example: STL Container Adaptors


STL - Standard template library for C++

STL has three basic container classes:

Vector

O(1) access time per object
O(1) growth at the bottom

Linked List
O(N) access time per object
O(1) growth anywhere

Deque
O(2) access time per object
O(1) growth at the bottom or top

The memory requirements for Linked List and Deque are different


Doc 13, State and Strategy Slide # 16
STL has the following container adaptors:

Stack, queue, and priority queue

One can implement a Stack with either a Vector, linked-list or a deque

Under different situations each can be better than the other two

class Stack
     {
     Container myStorage;
     
     public Stack( Container storage )
          {
          myStorage = storage;
          }
          
     public void push( Object item )
          {
          myStorage.append( item );
          }

     public Object push( Object item )
          {
          return myStorage.removeEnd(  );
          }
     }
     

Doc 13, State and Strategy Slide # 17
abstract class Container { public append( Object item ); public Object removeEnd(); etc. } class Vector extends Container { public append( Object item ); { add the code here } public Object removeEnd() { add the code here } }


Doc 13, State and Strategy Slide # 18

Applicability


Use the Strategy pattern when


Consequences


Families of related algorithms

Alternative to subclassing

Eliminates conditional statements

Gives a choice of implementations

Clients must be aware of different Strategies

Communication overhead between Strategy and Context

Increase number of objects


Doc 13, State and Strategy Slide # 19

Implementation


Defining the Strategy and Context interfaces

How does data flow between them

Strategies as template parameters


Making Strategy objects optional
----------