zahra moslehi amirkabir university of technology, department of computer engineering &...
Post on 19-Dec-2015
217 views
TRANSCRIPT
STATE PATTERN
Zahra MoslehiAmirKabir University of Technology,
Department of Computer Engineering & Information Technology
Advanced design pattern Course
Fall 2010
Design Pattern Course
INTENT
Allow an object to alter its behavior when its internal state changes
Also known as: Objects for States
MOTIVATION
The class TCPConnection delegates all state-specific requests to this state object
TheTCPState class declares an interface common to all classes that represent different operational states
the classes TCPEstablished and TCPClosed implement behavior particular to theEstablished and Closed states of TCPConnection
APPLICABILITY
An object's behavior depends on its state
An object must change its behavior at run-time depending on that state
Operations have large, multipart conditional statements that depend on the object's state
PARTICIPANTS
Context (TCPConnection) maintains an instance of a ConcreteState
subclass that defines the current state. clients don't have to deal with the State
objects directly State (TCPState)
defines an interface for encapsulating the behavior associated with a particular state of the Context.
ConcreteState subclasses (TCPEstablished, TCPListen, TCPClosed) each subclass implements a behavior
associated with a state of the Context.
CONSEQUENCES
Benefits Puts all behavior associated with a state into one
object new states and transitions can be added easily by
defining new subclasses State objects can be shared It makes state transitions explicit Helps avoid inconsistent states since state
changes occur using just the one state object and not several objects or attributes
It eliminates the necessity for a set of long, look-alike conditional
statements scattered through the program’s code. in the process, simplifies and clarifies the program
IMPLEMENTATION
How can the state object store its state elsewhere? Have the Context store this data and pass it to
the state object (a push model) Have the Context store this data and have the
state object retrieve it when needed ( a pull model)
Consider a simplified version of the Post Office Protocol used to
download e-mail from a mail server Simple POP (SPOP) supports the following
command: USER username
The USER command with a username must be the first command issued
PASS password The PASS command with a password or the
QUIT command must come after USER. If the username and password are valid, then
the user can use other commands.
SAMPLE CODE(EXAMPLE1)
LIST <message number> The LIST command returns the size of all
messages in the mail box If the optional message number is specified,
then it returns the size of that message. RETR <message number>
The RETR command retrieves all message in the mail box
If the optional message number is specified, then it retrieves that message.
QUIT The QUIT command updates the mail box to
reflect transactions taken, then logs the user out.
SAMPLE CODE(EXAMPLE1)
Here's a version of an SPop class without using the State pattern:
public 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;
SAMPLE CODE(EXAMPLE1)
public void user(String userName) {switch (state) {
case START: {this.userName = userName;state = HAVE_USER_NAME;break;}
default: { // Invalid commandsendErrorMessageOrWhatEver();endLastSessionWithoutUpdate();userName = null;password = null;state = START;
}}
}
SAMPLE CODE(EXAMPLE1)
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;
}
}}...
SAMPLE CODE(EXAMPLE1)
a push modelpublic class SPopState {
public SPopState user(String userName) {default action here}public SPopState pass(String password) {default action here}public SPopState list(int messageNumber) {default action here}public SPopState retr(int messageNumber) {default action here}public SPopState quit() {default action here}
}public class Start extends SPopState {
public SPopState user(String userName) {return new HaveUserName(userName);
}
}
SAMPLE CODE(EXAMPLE1)
public 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);
elsereturn new Start();
}}
SAMPLE CODE(EXAMPLE1)
public 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(messageNumber);}...
}
SAMPLE CODE(EXAMPLE1)
a pull modelpublic class SPop {
private SPopState state = new Start();String userName;String password;public String getUserName() {return userName;}public String getPassword() {return password;}public void user(String newName) {this.userName = newName ;state.user(this);}...
}
SAMPLE CODE(EXAMPLE1)
public class HaveUserName extends SPopState {public SPopState user(SPop mailServer) {String userName = mailServer.getUserName();...}...
}
SAMPLE CODE(EXAMPLE1)
class FSM {
State state;public FSM(State s) { state = s; }public void move(char c) { state =
state.move(c); }public boolean accept() { return state.accept();}
}public interface State {
State move(char c);boolean accept();
}
SAMPLE CODE(EXAMPLE3)
class State1 implements State {static State1 instance = new State1();private State1() {}public State move (char c) {
switch (c) {case 'a': return State2.instance;case 'b': return State1.instance;default: throw newIllegalArgumentException();}
}public boolean accept() {return false;}
}
SAMPLE CODE(EXAMPLE3)
class State2 implements State {static State2 instance = new State2();private State2() {}public State move (char c) {
switch (c) {case 'a': return State1.instance;case 'b': return State1.instance;default: throw newIllegalArgumentException();}
}public boolean accept() {return true;}
}
SAMPLE CODE(EXAMPLE3)
class AbstractTool is function moveTo(point) is input: the location point the mouse moved to (this function must be implemented by subclasses) function mouseDown(point) is input: the location point the mouse is at (this function must be implemented by subclasses) function mouseUp(point) is input: the location point the mouse is at (this function must be implemented by subclasses)
SAMPLE CODE(EXAMPLE4)
subclass PenTool of AbstractTool is last_mouse_position := invalid mouse_button := up function moveTo(point) is input: the location point the mouse moved to if mouse_button = down (draw a line from the last_mouse_position to point) last_mouse_position := point function mouseDown(point) is input: the location point the mouse is at mouse_button := down last_mouse_position := point function mouseUp(point) is input: the location point the mouse is at mouse_button := up
SAMPLE CODE(EXAMPLE4)
subclass SelectionTool of AbstractTool is selection_start := invalid mouse_button := up function moveTo(point) is input: the location point the mouse moved to if mouse_button = down (select the rectangle between selection_start and point) function mouseDown(point) is input: the location point the mouse is at mouse_button := down selection_start := point function mouseUp(point) is input: the location point the mouse is at mouse_button := up
SAMPLE CODE(EXAMPLE4)
class Cursor is current_tool := new PenTool function moveTo(point) is input: the location point the mouse moved to current_tool.moveTo(point) function mouseDown(point) is input: the location point the mouse is at current_tool.mouseDown(point) function mouseUp(point) is input: the location point the mouse is at current_tool.mouseUp(point) function usePenTool() is current_tool := new PenTool function useSelectionTool() is current_tool := new SelectionTool
SAMPLE CODE(EXAMPLE4)