实现有状态对象或状态机
想实现一个状态机或可以在许多不同状态下运行的对象,但又不想在代码中添加很多条件。
一般通过添加不同状态符号来运行不同状态下的代码,如下:
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())总是在进行操作之前检查状态,因此性能会降低。
一种更优雅的方法是将每个操作状态编码为一个单独的类,并安排Connection类委派给该状态类。如下:
class Connection:
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()
print(c._state)
c.open()
c.read()
print(c._state)
c.read()
c.write('hello')
c.close()
print(c._state)
------------------------------------------
<class '__main__.ClosedConnectionState'>
reading
<class '__main__.OpenConnectionState'>
reading
writing
<class '__main__.ClosedConnectionState'>
另一种实现技术涉及对实例的__class__属性的直接操作:
class Connection:
def __init__(self):
self.new_state(ClosedConnection)
def new_state(self, newstate):
self.__class__ = newstate
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)
c = Connection()
print(c)
c.open()
print(c)
c.close()
print(c)
------------------------------------------
<__main__.ClosedConnection object at 0x7fd57c2603d0>
<__main__.OpenConnection object at 0x7fd57c2603d0>
<__main__.ClosedConnection object at 0x7fd57c2603d0>
这种方案修改类实例的__class__属性,看似违背了面向对象的基本原则,但从技术上是可行的。此外,由于Connection上的所有方法都不再涉及额外的委派步骤,因此这可能会导致代码速度更快。