W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
你想實(shí)現(xiàn)一個(gè)狀態(tài)機(jī)或者是在不同狀態(tài)下執(zhí)行操作的對(duì)象,但是又不想在代碼中出現(xiàn)太多的條件判斷語(yǔ)句。
在很多程序中,有些對(duì)象會(huì)根據(jù)狀態(tài)的不同來(lái)執(zhí)行不同的操作。比如考慮如下的一個(gè)連接對(duì)象:
class Connection:
"""普通方案,好多個(gè)判斷語(yǔ)句,效率低下~~"""
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'
這樣寫(xiě)有很多缺點(diǎn),首先是代碼太復(fù)雜了,好多的條件判斷。其次是執(zhí)行效率變低,因?yàn)橐恍┏R?jiàn)的操作比如read()、write()每次執(zhí)行前都需要執(zhí)行檢查。
一個(gè)更好的辦法是為每個(gè)狀態(tài)定義一個(gè)對(duì)象:
class Connection1:
"""新方案——對(duì)每個(gè)狀態(tài)定義一個(gè)類"""
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'>
>>>
如果代碼中出現(xiàn)太多的條件判斷語(yǔ)句的話,代碼就會(huì)變得難以維護(hù)和閱讀。這里的解決方案是將每個(gè)狀態(tài)抽取出來(lái)定義成一個(gè)類。
這里看上去有點(diǎn)奇怪,每個(gè)狀態(tài)對(duì)象都只有靜態(tài)方法,并沒(méi)有存儲(chǔ)任何的實(shí)例屬性數(shù)據(jù)。實(shí)際上,所有狀態(tài)信息都只存儲(chǔ)在 Connection
實(shí)例中。在基類中定義的 NotImplementedError
是為了確保子類實(shí)現(xiàn)了相應(yīng)的方法。這里你或許還想使用8.12小節(jié)講解的抽象基類方式。
設(shè)計(jì)模式中有一種模式叫狀態(tài)模式,這一小節(jié)算是一個(gè)初步入門(mén)!
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: