-
Notifications
You must be signed in to change notification settings - Fork 91
/
Copy pathstate.py
134 lines (101 loc) · 3.61 KB
/
state.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Code Listing #16
"""
State pattern - Using a computer and its state as an example.
The implementation technique uses an iterator.
"""
import random
import itertools
class ComputerState(object):
""" Base class for state of a computer """
# This is an iterator
name = "state"
next_states = []
random_states = []
def __init__(self):
self.index = 0
def __str__(self):
return self.__class__.__name__
def __iter__(self):
return self
def change(self):
return self.__next__()
def set(self, state):
""" Set a state """
if self.index < len(self.next_states):
if state in self.next_states:
# Set index
self.index = self.next_states.index(state)
self.__class__ = eval(state)
return self.__class__
else:
# Raise an exception for invalid state change
current = self.__class__
new = eval(state)
raise Exception('Illegal transition from %s to %s' % (current, new))
else:
self.index = 0
if state in self.random_states:
self.__class__ = eval(state)
return self.__class__
def __next__(self):
""" Switch to next state """
if self.index < len(self.next_states):
# Always move to next state first
self.__class__ = eval(self.next_states[self.index])
# Keep track of the iterator position
self.index += 1
return self.__class__
else:
# Can switch to a random state once it completes
# list of mandatory next states.
# Reset index
self.index = 0
if len(self.random_states):
state = random.choice(self.random_states)
self.__class__ = eval(state)
return self.__class__
else:
raise StopIteration
class ComputerOff(ComputerState):
next_states = ['ComputerOn']
random_states = ['ComputerSuspend', 'ComputerHibernate', 'ComputerOff']
class ComputerOn(ComputerState):
random_states = ['ComputerSuspend', 'ComputerHibernate', 'ComputerOff']
class ComputerWakeUp(ComputerState):
random_states = ['ComputerSuspend', 'ComputerHibernate', 'ComputerOff']
class ComputerSuspend(ComputerState):
next_states = ['ComputerWakeUp']
random_states = ['ComputerSuspend', 'ComputerHibernate', 'ComputerOff']
class ComputerHibernate(ComputerState):
next_states = ['ComputerOn']
random_states = ['ComputerSuspend', 'ComputerHibernate', 'ComputerOff']
class Computer(object):
""" A class representing a computer """
def __init__(self, model):
self.model = model
# State of the computer - default is off.
self.state = ComputerOff()
def change(self, state=None):
""" Change state """
if state==None:
return self.state.change()
else:
return self.state.set(state)
def __str__(self):
""" Return state """
return str(self.state)
if __name__ == "__main__":
c = Computer('ASUS')
print(c)
print(c.change())
print(c.change('ComputerHibernate'))
# Now since this is an iterator we can even loop it
print('Iterating')
for s in itertools.islice(c.state, 5):
print(s)
# Switch off
print(c.change('ComputerOff'))
print(c.change('ComputerOn'))
print(c.change('ComputerSuspend'))
# Will rais an exception!
print(c.change('ComputerHibernate'))