zahra moslehi amirkabir university of technology, department of computer engineering &...

31
STATE PATTERN Zahra Moslehi AmirKabir University of Technology, Department of Computer Engineering & Information Technology Advanced design pattern Course Fall 2010 Design Pattern Course

Post on 19-Dec-2015

217 views

Category:

Documents


0 download

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

STRUCTURE

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)

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)

Now let's use the State pattern!

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)

SAMPLE CODE(EXAMPLE2)

SAMPLE CODE(EXAMPLE3)

S1 S2S2

a

a/b

b

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)

RELATED PATTERNS

Flyweight Singleton

Thanks for your attention

؟