330 likes | 503 Views
Design Pattern Course. State Pattern. Zahra Moslehi AmirKabir University of Technology, Department of Computer Engineering & Information Technology Advanced design pattern Course Fall 2010. Intent. Allow an object to alter its behavior when its internal state changes Also known as:
E N D
Design Pattern Course State Pattern Zahra Moslehi AmirKabir University of Technology, Department of Computer Engineering & Information Technology Advanced design pattern Course Fall 2010
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
Consequences(cont) • Liabilities • Increased number of objects
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)
Sample code(Example1) • 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 command sendErrorMessageOrWhatEver(); 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) • Now let's use the State pattern!
Sample code(Example1) • a push model public class SPopState { public SPopState user(String userName) {default action here} public SPopState pass(String password) {default action here} public SPopState list(intmessageNumber) {default action here} public SPopStateretr(intmessageNumber) {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); else return 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(intmessageNumber) { state = state.list(messageNumber); } ... }
Sample code(Example1) • a pull model public 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(SPopmailServer) { String userName = mailServer.getUserName(); ... } ... }
a S2 S1 b a/b Sample code(Example3)
Sample code(Example3) 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 new IllegalArgumentException(); } } 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 new IllegalArgumentException(); } } public boolean accept() {return true;} }
Sample code(Example4) 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
Related Patterns • Flyweight • Singleton