CS 635: Advanced Object-Oriented Design & Programming |
---|
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 |
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.
SPOP supports the following command:
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
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
Returns: the mail message indicated by the number
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
USER | PASS | LIST | RETR | QUIT | |
Start | |||||
HaveUserName | |||||
Authorized |
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; } } }
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. }
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.
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 } }
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(); } }
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(); }Issue: Who defines the state transitions?
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
A state object can have no instance variables if:
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 ); }Storing Instance Variables Elsewhere
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. } }
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)
2. It makes state transitions explicit
3. State objects can be shared