You are on page 1of 21

The State Pattern

Luca Vigan
Dipartimento di Informatica Universit di Verona

Laboratorio di Ingegneria del Software 27.05.2011

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

1 / 21

Problem description: gumball machine


Here is the way we think a gumball machine controller needs to work. Were hoping you can implement this in Java for us! We may be adding more behavior in the future, so you need to keep the design as exible and maintainable as possible!

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

2 / 21

State Machines 101

How are we going to get from that state diagram or actual code? Heres a quick introduction to implementing state machines:
1. First, gather up your state:
a. b. c. d. No Quarter Has Quarter Out of Gumballs Gumball Sold

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

3 / 21

State Machines 101

2. Next, create an instance variable to hold the current state, and dene values for each of the states:
/ / each s t a t e r e p r e s e n t e d as a unique i n t e g e r : f i n a l s t a t i c i n t SOLD_OUT = 0 ; f i n a l s t a t i c i n t NO_QUARTER = 1 ; f i n a l s t a t i c i n t HAS_QUARTER = 2 ; f i n a l s t a t i c i n t SOLD = 3 ; / Instance v a r i a b l e t h a t holds the c u r r e n t s t a t e . We l l go ahead and s e t i t t o " Sold Out " s i n c e t h e machine w i l l be u n f i l l e d when i t s f i r s t taken o u t o f i t s box and t u r n e d on . / i n t s t a t e = SOLD OUT;

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

4 / 21

State Machines 101

3. Now we gather up all the actions that can happen in the system:
a. b. c. d. insert quarter eject quarter turns crank dispense

These actions are the gumball machines interface: the things you can do with it. Dispense is however more of an internal action the machine invokes on itself. Invoking any of these actions causes a state transition.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

5 / 21

State Machines 101


4. Now we create a class that acts as the state machine. For each action, we create a method that uses conditional statements to determine what behavior is appropriate in each state. For instance, for the insert quarter action, we might write a method like this:
public void i n s e r t Q u a r t e r ( ) { i f ( s t a t e == HAS_QUARTER) { System . o u t . p r i n t l n ( " You can t i n s e r t a n o t h e r q u a r t e r " ) ; } else i f ( s t a t e == NO_QUARTER) { s t a t e = HAS_QUARTER; System . o u t . p r i n t l n ( " You i n s e r t e d a q u a r t e r " ) ; } else i f ( s t a t e == SOLD_OUT) { System . o u t . p r i n t l n ( " You can t i n s e r t a q u a r t e r , t h e machine i s s o l d o u t " ) ; } else i f ( s t a t e == SOLD) { System . o u t . p r i n t l n ( " Please w a i t , we r e a l r e a d y g i v i n g you a gumball " ) ; } }

Each possible state is checked with a conditional statement, exhibits the appropriate behavior for each possible state, can also transition to other states.
Luca Vigan (Universit di Verona) The State Pattern Lab. Ing. del SW, 27.05.2011 6 / 21

Implement the code and then... a change request

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

7 / 21

Design Puzzle: turn gumball buying into a game


A state diagram for a Gumball Machine that handles the 1 in 10 contest.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

8 / 21

The messy state of things...

Look at your code and think about what youll have to do to modify it:
First, youd have to add a new winner state here. That isnt too bad... ... but then, youd have to add a new conditional in every single method to handle the winner state: thats a lot of code to modify... ... turnCrank() will get especially messy, because youd have to add code to check to see whether youve got a winner and then switch to either the winner state of the sold state.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

9 / 21

The new design

Were going to rework the code to encapsulate state objects in their own classes and then delegate to the current state when an action occurs.
1

First, were going to dene a State interface that contains a method for every action in the Gumball Machine. Then were going to implement a State class for every state of the machine. These classes will be responsible for the behavior of the machine when it is in the corresponding state. Finally, were going to get rid of all of our conditional code and instead delegate to the state class to do the work for us.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

10 / 21

Dening the State Interfaces and classes

First lets create an Interface for State, which all our states implement, and then take each state in our design and encapsulate it in a class that implements the State interface.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

11 / 21

Dening the State Interfaces and classes

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

12 / 21

Sharpen your pencil

To implement our states, we rst need to specify the behavior of the classes when each action is called. Write the behavior of each action in each class...

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

13 / 21

The State Pattern dened


The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class. The rst part of this description makes a lot of sense, right? Because the pattern encapsulates state into separate classes and delegates to the object representing the current state, we know that behavior changes along with the internal state. The Gumball Machine provides a good example: when the gumball machine is in the NoQuarterState and you insert a quarter, you get different behavior (the machine accepts the quarter) than if you insert a quarter when its in the HasQuarterState (the machine rejects the quarter). What about the second part of the denition? What does it mean for an object to appear to change its class?
Luca Vigan (Universit di Verona) The State Pattern Lab. Ing. del SW, 27.05.2011 14 / 21

The State Pattern dened (2)

Think about it from the perspective of a client: if an object youre using can completely change its behavior, then it appears to you that the object is actually instantiated from another class. In reality, however, you know that we are using composition to give the appearance of a class change by simply referencing different state objects.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

15 / 21

State Pattern class diagram

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

16 / 21

The State Pattern and the Strategy Pattern

The class diagrams of Strategy Pattern and the State Pattern are essentially the same, but the two patterns differ in their intent. With the State Pattern, we have a set of behaviors encapsulated in state objects; at any time the context is delegating to one of those states. Over time, the current state changes across the set of state objects to reect the internal state of the context, so the contexts behavior changes over time as well. The client usually knows very little, if anything, about the state objects.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

17 / 21

The State Pattern and the Strategy Pattern


With Strategy, the client usually species the strategy object that the context is composed with. Now, while the pattern provides the exibility to change the strategy object at runtime, often there is a strategy object that is most appropriate for a context object. For instance, some of our ducks were congured to y with typical ying behavior (like mallard ducks), while others were congured with a y behavior that kept them grounded (like rubber ducks and decoy ducks). In general, think of the Strategy Pattern as a exible alternative to subclassing. If you use inheritance to dene the behavior of a class, then youre stuck with that behavior even if you need to change it. With Strategy you can change the behavior by composing with a different object.
Luca Vigan (Universit di Verona) The State Pattern Lab. Ing. del SW, 27.05.2011 18 / 21

The State Pattern and the Strategy Pattern

Think of the State Pattern as an alternative to putting lots of conditionals in your context: by encapsulating the behaviors within state objects, you can simply change the state object in context to change its behavior.

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

19 / 21

Now nish the Gumball 1 in 10 game...

Need to add the WinnerState in GumballMachine class:


1 2

Write the WinnerState class Modify the HasQuarterState class

... thats it!

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

20 / 21

...and add the rell


Write the rell() method for the Gumball machine. It has one argument: the number of gumballs youre adding to the machine, and should update the gumball machine count and reset the machines state

Luca Vigan (Universit di Verona)

The State Pattern

Lab. Ing. del SW, 27.05.2011

21 / 21

You might also like