8.19 实现状�对象或者状�机¶
问题¶
ä½ æƒ³å®žçŽ°ä¸€ä¸ªçŠ¶æ€�机或者是在ä¸�å�Œçжæ€�下执行æ“�作的对象,但是å�ˆä¸�想在代ç �ä¸å‡ºçŽ°å¤ªå¤šçš„æ�¡ä»¶åˆ¤æ–è¯å�¥ã€‚
解决方案¶
在很多程åº�ä¸ï¼Œæœ‰äº›å¯¹è±¡ä¼šæ ¹æ�®çжæ€�çš„ä¸�å�Œæ�¥æ‰§è¡Œä¸�å�Œçš„æ“�作。比如考虑如下的一个连接对象:
class Connection:
"""普通方案,好多个判æ–è¯å�¥ï¼Œæ•ˆçŽ‡ä½Žä¸‹~~"""
def __init__(self):
self.state = 'CLOSED'
def read(self):
if self.state != 'OPEN':
raise RuntimeError('Not open')
print('reading')
def write(self, data):
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'
è¿™æ ·å†™æœ‰å¾ˆå¤šç¼ºç‚¹ï¼Œé¦–å…ˆæ˜¯ä»£ç �太å¤�æ�‚了,好多的æ�¡ä»¶åˆ¤æ–。其次是执行效率å�˜ä½Žï¼Œ å› ä¸ºä¸€äº›å¸¸è§�çš„æ“�作比如read()ã€�write()æ¯�次执行å‰�都需è¦�执行检查。
一个更好的办法是为�个状�定义一个对象:
class Connection1:
"""新方案——对�个状�定义一个类"""
def __init__(self):
self.new_state(ClosedConnectionState)
def new_state(self, newstate):
self._state = newstate
# Delegate to the state class
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)
# Connection state base class
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()
# Implementation of different states
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)
下�是使用演示:
>>> c = Connection()
>>> c._state
<class '__main__.ClosedConnectionState'>
>>> c.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "example.py", line 10, in read
return self._state.read(self)
File "example.py", line 43, in read
raise RuntimeError('Not open')
RuntimeError: Not open
>>> c.open()
>>> c._state
<class '__main__.OpenConnectionState'>
>>> c.read()
reading
>>> c.write('hello')
writing
>>> c.close()
>>> c._state
<class '__main__.ClosedConnectionState'>
>>>
讨论¶
如果代ç �ä¸å‡ºçŽ°å¤ªå¤šçš„æ�¡ä»¶åˆ¤æ–è¯å�¥çš„è¯�,代ç �就会å�˜å¾—难以维护和阅读。 这里的解决方案是将æ¯�个状æ€�抽å�–出æ�¥å®šä¹‰æˆ�一个类。
这里看上去有点奇怪,æ¯�个状æ€�对象都å�ªæœ‰é�™æ€�方法,并没有å˜å‚¨ä»»ä½•的实例属性数æ�®ã€‚
实际上,所有状æ€�ä¿¡æ�¯éƒ½å�ªå˜å‚¨åœ¨ Connection 实例ä¸ã€‚
在基类ä¸å®šä¹‰çš„ NotImplementedError 是为了确ä¿�å�类实现了相应的方法。
è¿™é‡Œä½ æˆ–è®¸è¿˜æƒ³ä½¿ç”¨8.12å°�节讲解的抽象基类方å¼�。
设计模å¼�䏿œ‰ä¸€ç§�模å¼�å�«çжæ€�模å¼�,这一å°�节算是一个åˆ�æ¥å…¥é—¨ï¼�