Skip to content

Commit 76d5ff6

Browse files
committed
implemented gumball machine state pattern
1 parent ac9a1d0 commit 76d5ff6

File tree

2 files changed

+187
-1
lines changed

2 files changed

+187
-1
lines changed

chapter01_strategy/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> **Strategy**: defines a family of algorithms, encapsulates each one and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
44
5-
<details><summary>Class Diagram</summary><p>
5+
<details><summary>Class Diagram (install mermaid to view)</summary><p>
66

77
```mermaid
88
classDiagram

chapter10_state/gumballstate.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
class GumballMachine:
2+
def __init__(self, number_gumballs) -> None:
3+
self.no_quarter_state = NoQuarterState(self)
4+
self.sold_out_state = SoldOutState(self)
5+
self.has_quarter_state = HasQuarterState(self)
6+
self.sold_state = SoldState(self)
7+
self.count = number_gumballs
8+
if number_gumballs > 0:
9+
self.state = self.no_quarter_state
10+
else:
11+
self.state = self.sold_out_state
12+
13+
def insert_quarter(self):
14+
self.state.insert_quarter()
15+
16+
def eject_quarter(self):
17+
self.state.eject_quarter()
18+
19+
def turn_crank(self):
20+
self.state.turn_crank()
21+
self.state.dispense()
22+
23+
def release_ball(self):
24+
print("A gumball comes rolling out the slot...")
25+
if self.count > 0:
26+
self.count -= 1
27+
28+
def refill(self, count):
29+
self.count += count
30+
print(f"The gumball machine was just refilled; its new count is: {self.count}")
31+
self.state.refill()
32+
33+
def set_state(self, state):
34+
self.state = state
35+
36+
def __str__(self) -> str:
37+
result = []
38+
result.append("\nMighty Gumball, Inc.")
39+
result.append("\nJava-enabled Standing Gumball Model #2004")
40+
result.append(f"\nInventory: {self.count} gumball")
41+
if self.count != 1:
42+
result.append("s")
43+
44+
result.append("\n")
45+
result.append(f"Machine is {self.state}\n")
46+
return "".join(result)
47+
48+
49+
class State:
50+
def insert_quarter(self):
51+
raise NotImplementedError
52+
53+
def eject_quarter(self):
54+
raise NotImplementedError
55+
56+
def turn_crank(self):
57+
raise NotImplementedError
58+
59+
def dispense(self):
60+
raise NotImplementedError
61+
62+
def refill(self):
63+
raise NotImplementedError
64+
65+
66+
class NoQuarterState(State):
67+
def __init__(self, gumball_machine: GumballMachine) -> None:
68+
self.gumball_machine = gumball_machine
69+
70+
def insert_quarter(self):
71+
print("You inserted a quarter")
72+
self.gumball_machine.set_state(self.gumball_machine.has_quarter_state)
73+
74+
def eject_quarter(self):
75+
print("You haven't inserted a quarter")
76+
77+
def turn_crank(self):
78+
print("You turned, but there's no quarter")
79+
80+
def dispense(self):
81+
print("You need to pay first")
82+
83+
def refill(self):
84+
raise NotImplementedError
85+
86+
def __str__(self):
87+
return "waiting for quarter"
88+
89+
90+
class SoldOutState(State):
91+
def __init__(self, gumball_machine: GumballMachine) -> None:
92+
self.gumball_machine = gumball_machine
93+
94+
def insert_quarter(self):
95+
print("You can't insert a quarter, the machine is sold out")
96+
97+
def eject_quarter(self):
98+
print("You can't eject, you haven't inserted a quarter yet")
99+
100+
def turn_crank(self):
101+
print("You turned, but there are no gumballs")
102+
103+
def dispense(self):
104+
print("No gumball dispensed")
105+
106+
def refill(self):
107+
self.gumball_machine.set_state(self.gumball_machine.no_quarter_state)
108+
109+
def __str__(self):
110+
return "sold out"
111+
112+
113+
class HasQuarterState(State):
114+
def __init__(self, gumball_machine: GumballMachine) -> None:
115+
self.gumball_machine = gumball_machine
116+
117+
def insert_quarter(self):
118+
print("You can't insert another quarter")
119+
120+
def eject_quarter(self):
121+
print("Quarter returned")
122+
self.gumball_machine.set_state(self.gumball_machine.no_quarter_state)
123+
124+
def turn_crank(self):
125+
print("You turned...")
126+
self.gumball_machine.set_state(self.gumball_machine.sold_state)
127+
128+
def dispense(self):
129+
print("No gumball dispensed")
130+
131+
def refill(self):
132+
raise NotImplementedError
133+
134+
def __str__(self):
135+
return "waiting for turn of crank"
136+
137+
138+
class SoldState(State):
139+
def __init__(self, gumball_machine: GumballMachine) -> None:
140+
self.gumball_machine = gumball_machine
141+
142+
def insert_quarter(self):
143+
print("Please wait, we're already giving you a gumball")
144+
145+
def eject_quarter(self):
146+
print("Sorry, you already turned the crank")
147+
148+
def turn_crank(self):
149+
print("Turning twice doesn't get you another gumball!")
150+
151+
def dispense(self):
152+
self.gumball_machine.release_ball()
153+
if self.gumball_machine.count > 0:
154+
self.gumball_machine.set_state(self.gumball_machine.no_quarter_state)
155+
else:
156+
self.gumball_machine.set_state(self.gumball_machine.sold_out_state)
157+
158+
def refill(self):
159+
raise NotImplementedError
160+
161+
def __str__(self):
162+
return "dispensing a gumball"
163+
164+
165+
def gumball_machine_test_drive():
166+
gumball_machine = GumballMachine(2)
167+
print(gumball_machine)
168+
gumball_machine.insert_quarter()
169+
gumball_machine.turn_crank()
170+
171+
print(gumball_machine)
172+
173+
gumball_machine.insert_quarter()
174+
gumball_machine.turn_crank()
175+
gumball_machine.insert_quarter()
176+
gumball_machine.turn_crank()
177+
178+
gumball_machine.refill(5)
179+
gumball_machine.insert_quarter()
180+
gumball_machine.turn_crank()
181+
182+
print(gumball_machine)
183+
184+
185+
if __name__ == "__main__":
186+
gumball_machine_test_drive()

0 commit comments

Comments
 (0)