实现带有状态的对象


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 一个naive的例子
class Connection:
def __init__(self):
self.state = 'CLOSED'
def read(self):
if self.state != 'OPEN':
raise RuntimeError('Not open')
print('reading')
def write(self):
if self.state != 'OPEN':
raise RuntimeError('Not open')
print('writing')
def open(self):
if self.state == 'OPEN':
raise RuntimeError('Already open')
self.state = 'OPEN'
def close(self):
if self.state == 'CLOSED':
raise RuntimeError('Already CLOSED')
self.state = 'CLOSED'

这样很不优雅,而且包含了大量重复的代码。
我们的目的是进行状态判断,那么我们本就可以把OPEN跟CLOSE状态各自封装成一个类。

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
# Connection state 的基类
class ConnectionState:
@staticmethod
def read(conn):
raise NotImplementedError()
@staticmethod
def write(conn, data):
raise NotImplementedError()
@staticmethod
def open(conn):
raise NotImplementedError()
@staticmethod
def close(conn):
raise NotImplementedError()
# 不同状态
class ClosedConnectionState(ConnectionState):
@staticmethod
def read(conn):
raise RuntimeError('Not open')
@staticmethod
def write(conn, data):
raise RuntimeError('Not open')
@staticmethod
def open(conn):
conn.new_state(OpenConnectionState)
@staticmethod
def close(conn):
raise RuntimeError('Already closed')
class OpenConnectionState(ConnectionState):
@staticmethod
def read(conn):
print('reading')
@staticmethod
def write(conn, data):
print('writing')
@staticmethod
def open(conn):
raise RuntimeError('Already open')
@staticmethod
def close(conn):
conn.new_state(ClosedConnectionState)
class Connection:
def __init__(self):
self.new_state(ClosedConnectionState)
def new_state(self, newstate):
self._state = newstate
def read(self):
return self._state.read(self)
def write(self, data):
return self._state.write(self, data)
def open(self):
return self._state.open(self)
def close(self):
return self._state.close(self)
if __name__ == '__main__':
c = Connection()
print(c)
try:
c.read()
except RuntimeError as e:
print(e)
c.open()
print(c)
c.read()
c.close()
print(c)

这里的每种状态都用类和静态方法来实现,在每个静态方法中都把Connection类的实例作为第一个参数。这是因为我们在不同的状态类中不保存任何实例数据,所有的实例数据都应该保存在Connection实例中。
再看看第二种方法,直接修改实例的class属性
这里不再将Connection和COnnectionState作为单独的类来实现,现在我们将他们合并在一起。随着状态的改变,实例也会修改自己的类型。

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
class Connection:
def __init__(self):
self.new_state(ClosedConnection)
def new_state(self, state):
self.__class__ = state
def read(self):
raise NotImplementedError()
def write(self, data):
raise NotImplementedError()
def open(self):
raise NotImplementedError()
def close(self):
raise NotImplementedError()
class ClosedConnection(Connection):
def read(self):
raise RuntimeError('Not open')
def write(self, data):
raise RuntimeError('Not open')
def open(self):
self.new_state(OpenConnection)
def close(self):
raise RuntimeError('Already closed')
class OpenConnection(Connection):
def read(self):
print('reading')
def write(self, data):
print('writing')
def open(self):
raise RuntimeError('Already open')
def close(self):
self.new_state(ClosedConnection)
if __name__ == '__main__':
c = Connection()
print(c)
try:
c.read()
except RuntimeError as e:
print(e)
c.open()
print(c)
c.read()
c.close()
print(c)

聪明的同学可能会看出,这TM就是设计模式中的状态模式嘛。

文章目录
|