9.3 State Pattern Lab

Overview

9.3 State Pattern Lab

This assignment is based on Head First Design Patterns: p. 385-423

Work through the stories in order. Use the acceptance criteria to check each feature, and complete the nested tasks using the specified names, values, and scenarios.

Getting Started
1.Getting Started
A Download and extract the start code.

9.3 State LastName.zip

9.3 State LastName.zip
B Explore the solution and run the application to see what it does.
Define State classes
Acceptance Criteria
Acceptance criteria
  • IState declares InsertQuarter, EjectQuarter, TurnCrank, and Dispense.
  • SoldState, SoldOutState, NoQuarterState, and HasQuarterState implement that contract and retain the GumballMachine reference.
Instructions
2.Define State classes

Currently the GumballMachine class has methods with very large conditional statements that control what happens. If we were to add another "state" to the gumball machine we would have to add logic to every single method. For every state we have the code gets larger and less manageable.

A Define classes based on the diagram below.
Class Diagram: State Classes; Members and relationships are shown in the editable reference; unrelated members may be omitted.
Class Diagram: State Classes
  • New
  • Changed
  • Removed
<<interface>> IState
InsertQuarter()
EjectQuarter()
TurnCrank()
Dispense()
Four following class will implement IState
SoldState
- gumballMachine: GumballMachine
+ SoldState (gumballMachine: GumballMachine)
+ InsertQuarter()
+ EjectQuarter()
+ TurnCrank()
+ Dispense()
SoldOutState
- gumballMachine: GumballMachine
+ SoldOutState (gumballMachine: Gumball Machine)
+ InsertQuarter()
+ EjectQuarter()
+ TurnCrank()
+ Dispense()
NoQuarterState
- gumball Machine: GumballMachine
+ NoQuarter State(gumballMachine: GumballMachine)
+ InsertQuarter()
+ EjectQuarter()
+ TurnCrank()
+ Dispense()
- gumballMachine: Gumball Machine
+ HasQuarter State (gumballMachine: GumballMachine)
+ InsertQuarter()
+ EjectQuarter()
+ TurnCrank()
+ Dispense()
B Put IState and all of the State classes in the States folder.
Modify the GumballMachine class to be composed of a particular state.
Acceptance Criteria
Acceptance criteria
  • The completed implementation satisfies this requirement: Assign the currentState field to the noQuarterState if the count is greater than 0 otherwise assign it to soldOutState.
  • GumballMachine exposes the required contract: soldOutState: IState; noQuarterState: IState; hasQuarterState: IState; soldState: IState.
Instructions
3.Modify the GumballMachine class to be composed of a particular state.
A Make changes to the GumballMachine class based on the diagram below.
Class Diagram: Gumball Machine; Members and relationships are shown in the editable reference; unrelated members may be omitted.
Class Diagram: Gumball Machine
  • New
  • Changed
  • Removed
GumballMachine
Remove the following fields
- HAS_QUARTERthe following fields
- HAS_QUARTER: : int <readonly>
- NO_QUARTER: : int <readonly>
- SOLD: : int <readonly>
- SOLD_OUT. int <readonly>
- state: : int
Add the following fields
- soldOutStatethe following fields
- soldOutState: : IState
- noQuarterState: : IState
- hasQuarter State: IState
- soldState: : IState
- currentState: : IState
Add the following properties
+ SoldOutStatethe following properties
+ SoldOutState: : IState <get>
+ NoQuarterState: : IState <get
+ HasQuarter State: IState <get>
+ SoldState: : IState <get>
+ CurrentState: : IState <get> <set>
B In the GumballMachine constructor,
1 Instantiate each State class, passing in this as the argument.

Each "state" class needs to have a reference to the GumballMachine object to modify it.

2 Assign the currentState field to the noQuarterState if the count is greater than 0 otherwise assign it to soldOutState.
Modify each of the State classes to handle the various behaviors.
Acceptance Criteria
Acceptance criteria
  • The completed implementation satisfies this requirement: Implement the NoQuarterState methods.
  • The completed implementation satisfies this requirement: Implement the SoldOutState methods.
  • The completed implementation satisfies this requirement: Implement the SoldState methods.
Instructions
4.Modify each of the State classes to handle the various behaviors.

For this step we are going to be breaking apart all of those huge if/else statements and putting them in their proper "state" class. The easiest way to accomplish this is to put the classes into split view.

A Implement the HasQuarterState class.
1 Cut the line of code from the InsertQuarter method in the GumballMachine class in the HAS_QUARTER condition and paste it…

Cut the line of code from the InsertQuarter method in the GumballMachine class in the HAS_QUARTER condition and paste it into the InsertQuarter method in the HasQuarterState class.

InsertQuarter for 9.3 State Pattern Lab. Use the adjacent task instructions to identify the required controls, output, or debugger values.
InsertQuarter
2 Cut the line of code from the Dispense method in the GumballMachine class in the HAS_QUARTER condition and paste it into the…

Cut the line of code from the Dispense method in the GumballMachine class in the HAS_QUARTER condition and paste it into the Dispense method in the HasQuarterState class.

3 Cut the lines of code from the EjectQuarter method in the GumballMachine class in the HAS_QUARTER condition and paste them…

Cut the lines of code from the EjectQuarter method in the GumballMachine class in the HAS_QUARTER condition and paste them into the EjectQuarter method in the HasQuarterState class.

4 In the EjectQuarter method in the HasQuarterState class, instead of the line that assigns state, assign the gumballMachine…

In the EjectQuarter method in the HasQuarterState class, instead of the line that assigns state, assign the gumballMachine object's CurrentState property to the gumballMachine object's NoQuarterState property.

Eject Quarter for 9.3 State Pattern Lab. Use the adjacent task instructions to identify the required controls, output, or debugger values.
Eject Quarter
5 Cut the lines of code from the TurnCrank method in the GumballMachine class in the HAS_QUARTER condition and paste them into…

Cut the lines of code from the TurnCrank method in the GumballMachine class in the HAS_QUARTER condition and paste them into the TurnCrank method in the HasQuarterState class.

6 In the TurnCrank method in the HasQuarterState class, instead of the line that assigns state*, assign the gumballMachine…

In the TurnCrank method in the HasQuarterState class, instead of the line that assigns state*, assign the gumballMachine object's CurrentState property to the gumballMachine object's SoldState property. Remove the call to Dispense.

Calling Dispense here wouldn't make much sense since in this "state" class the Dispense method prints out "No gumball dispensed".

B Implement the NoQuarterState methods.

The InsertQuarter method should be the only method that changes the state of the gumball machine.

C Implement the SoldOutState methods.

None of the methods should change the state of the gumball machine.

D In the GumballMachine class, add a method named ReleaseBall that reduces the count by 1 and write out "A gumball comes…

In the GumballMachine class, add a method named ReleaseBall that reduces the count by 1 and write out "A gumball comes rolling out of the slot".

E Implement the SoldState methods.

Add a Count getter to the GumballMachine class.

The Dispense method is the only method that should change the state of the gumball machine.

Modify the GumballMachine class.
Acceptance Criteria
Acceptance criteria
  • GumballMachine delegates quarter and crank actions to its current IState.
  • The old state-selection conditionals are removed from these client-facing methods.
  • State transitions still produce the expected dispensing behavior.
Instructions
5.Modify the GumballMachine class.
A Remove the Dispense method.
B Remove all the conditional statements from the EjectQuarter, TurnCrank and InsertQuarter methods.
C In the EjectQuarter method, call the currentState's EjectQuarter method.
D In the InsertQuarter method, call the currentState's InsertQuarter method.
E In the TurnCrank method, call the currentState's TurnCrank method and then the currentState's Dispense method.
Check Your Work:
Acceptance Criteria
Acceptance criteria
  • F11 on the first call to InsertQuarter. Ensure the debugger steps into the GumballMachine class.
  • Press F11 again. The debugger should go into the NoQuarterState class.
  • F11 through the method. The gumballMachine's currentState should now be HasQuarterState.
Instructions
6.Check Your Work:
A Set a breakpoint in the Main method on the line that instantiates the GumballMachine and start the application.
B Step through the GumballMachine constructor and make sure the states are instantiated and that the currentState is NoQuarterState.
Instantiated States for 9.3 State Pattern Lab. Use the adjacent task instructions to identify the required controls, output, or debugger values.
Instantiated States
C F11 on the first call to InsertQuarter. Ensure the debugger steps into the GumballMachine class.
D Press F11 again. The debugger should go into the NoQuarterState class.
E F11 through the method. The gumballMachine's currentState should now be HasQuarterState.
HasQuarterState for 9.3 State Pattern Lab. Use the adjacent task instructions to identify the required controls, output, or debugger values.
HasQuarterState
F Continue the application. The output should look like the image below.
Output for 9.3 State Pattern Lab. Use the adjacent task instructions to identify the required controls, output, or debugger values.
Output
Mighty Gumball, Inc.
Inventory.
Inventory: : 5
Machine is waiting for quarter...
.
You inserted a quarter
You turned...
.
A gumball comes rolling out out of the slot.
Mighty Gumball, Inc.
Inventory: : 4
Machine is waiting for quarter...
.
You inserted a quarter.
Quarter returned.
You turned but there's no quarter.
You need to pay first.
Mighty Gumball, Inc.
Inventory: : 4
Machine is waiting for quarter...
.
You inserted a quarter
You turned...
.
A gumball comes rolling out out of the slot.
You inserted a quarter
You turned...
.
A gumball comes rolling out out of the slot.
You haven't inserted a quarter.
Mighty Gumball, Inc.
Inventory: : 2
Machine is waiting for quarter...
.
You inserted a quarter
You can't insert another quarter.
You turned...
.
A gumball comes rolling out out of the slot.
You inserted a quarter
You turned...
.
A gumball comes rolling out out of the slot.
Oops, out out of gumballs!!
You can't insert a quarter, the machine is sold out.
You turned, but there are no gumballs.
No gumball dispensed.
Mighty Gumball, Inc.
Inventory: : 0
Machine is sold out.out.
Add a WinnerState to the gumball machine.
Acceptance Criteria
Acceptance criteria
  • Run the application. You output should look similar to the output shown below:
  • The completed implementation satisfies this requirement: Add a new class named WinnerState that implements IState and put it in the States folder.
  • The completed implementation satisfies this requirement: Add and instantiate a Random field.
Instructions
7.Add a WinnerState to the gumball machine.

Now that we have separated the states, it is going to be much easier to extend the functionality of either existing states or new states.

A Add a new class named WinnerState that implements IState and put it in the States folder.
B In the InsertQuarter, EjectQuarter and TurnCrank methods, copy and paste the method bodies from SoldState.
C In the Dispense method...
1 Print out "YOU'RE A WINNER! You get two gumballs for your quarter."
2 Call the ReleaseBall method.
3 If the machine's count is 0, assign the current state to the sold out state.
4 In the else statement....

Call ReleaseBall.

If the machine's count is greater than 0, assign the current state to the no quarter state.

Otherwise, print out "Oops, out of gumballs!" and assigns the current state to the sold out state.

D In the GumballMachine class, add a winnerState field and instantiate it in the constructor and a WinnerState property.
E In the HasQuarterState class...
1 Add and instantiate a Random field.
2 In the TurnCrank method after the WriteLine...

Store a random number in the a local variable named winner.

int winner = this.random.Next(10);

If the winner variable is 0 and the machine's count is greater than 1, assign the current state to the winner state.

Otherwise, assign the current state to the sold state.

Cut and paste the call that already existed otherwise the current state will always be the sold state.paste the call that already existed otherwise the current state will always be the sold state.
F Replace the code in Main with the code below:
GumballMachine gumballMachine = new GumballMachine(5);
Console.WriteLine(gumballMachine.ToString());
gumballMachine.InsertQuarter();
gumballMachine.TurnCrank();
Console.WriteLine(gumballMachine.ToString());
gumballMachine.InsertQuarter();
gumballMachine.TurnCrank();
gumballMachine.InsertQuarter();
gumballMachine.TurnCrank();
gumballMachine.InsertQuarter();
gumballMachine.TurnCrank();
Console.WriteLine(gumballMachine.ToString());
Console.Read();
G Check Your Work:

We suggest stepping through the code but aren't going to explicitly do it here.

1 Run the application. You output should look similar to the output shown below:
Output for 9.3 State Pattern Lab. Use the adjacent task instructions to identify the required controls, output, or debugger values.
Output

Since the winner is random it may take you several runs to get a winning result.

Mighty Gumball, Inc.
Inventory.
Inventory: : 5
Machine is waiting for quarter...
.
You inserted a quarter
You turned...
.
A gumball comes rolling out out of the slot.
Mighty Gumball, Inc.
Inventory: : 4
Machine is waiting for quarter...
.
You inserted a quarter.
You turned...
.
A gumball comes rolling out out of the slot.
You inserted a quarter.
You turned...
.
YOU'RE A WINNER! You get two gumballs for your quarter.
A gumball comes rolling out out of the slot.
A gumball comes rolling out out of the slot.
You inserted a quarter.
You turned...
.
A gumball comes rolling ouf of the slot.
Oops, out out of gumballs!!
Mighty Gumball, Inc.
Inventory: : 0
Machine is sold out.out.
Zip your application and submit to Canvas.
8.Zip your application and submit to Canvas.
A Zip your application and submit to Canvas.
Completion review
9.Review the feature acceptance criteria
A Confirm the required results

Return to each story and verify its acceptance criteria. Preserve the submission format and destination stated in the activity; a reading, setup guide, lab, video demonstration, and oral final may require different evidence.

Define State classes Modify the GumballMachine class to be composed of a particular state. Modify each of the State classes to handle the various behaviors. Modify the GumballMachine class. Check Your Work: Add a WinnerState to the gumball machine.