責任鏈模式(Chain of Responsibility Pattern)可將請求的發送方與處理請求的接收方解耦。這樣的話,某函數就不用直接調用別的函數了,而是可以把請求發送給一個由諸多接收者所組成的鏈條。鏈條中的首個接收者可以處理請求並停止責任鏈(也就是不再繼續往下傳遞),也可以把請求發給下一個接收者。而第二個接收者也有這兩種選擇,此過程可一直延續至最後一個接收者,該接收者可將請求丟棄,也可拋出異常。
使用常規方法實現
#!/usr/bin/env python
# encoding:utf-8
class NullHandler(object):
def __init__(self, successor=None):
self.__successor = successor
def handle(self, event):
if self.__successor is not None:
self.__successor.handle(event)
class ConcreteHandler1(NullHandler):
def handle(self, event):
if event > 0 and event <= 10:
print "in handler1", event
else:
super(ConcreteHandler1, self).handle(event)
class ConcreteHandler2(NullHandler):
def handle(self, event):
if event > 10 and event <= 20:
print "in handler2", event
else:
super(ConcreteHandler2, self).handle(event)
class ConcreteHandler3(NullHandler):
def handle(self, event):
if event > 20 and event <= 30:
print "in handler3", event
else:
super(ConcreteHandler3, self).handle(event)
def main():
handler = ConcreteHandler3(ConcreteHandler2(ConcreteHandler1(NullHandler())))
events = [2, 5, 14, 22, 18, 3, 35, 27, 20]
for event in events:
handler.handle(event)
所示代碼在NullHandler
設置一個successor
屬性,使用它來執行handle
,而其他則繼承NullHandler
,這樣不符合自身條件將它拋給NullHandler
,讓它來執行successor
的handle
。我們可以從上面賦值中看出successor
的順序,一開始最裏面successor
爲None
,後面是ConcreteHandler1
類型…依次類推,實現責任鏈。
使用協程實現責任鏈
協程(coroutine)與生成器一樣,也使用yield
表達式,但行爲不同。協程執行的是無限循環,而且一開始就會停在首個(或僅有的那個)yield
表達式那裏,等值有值傳給它。協程會把收到的值當成yield
表達式的值,然後繼續執行它所需的操作,等處理完之後,又會再度循環,並在下一個yield
表達式那裏等着接收下個值。這樣的話,我們就能反覆調用協程中的send()
或throw()
方法向其push
值。
在Python中,凡是帶有yield
語句的函數或方法都能充當生成器。而利用@coroutine
裝飾器及無限循環則可將生成器變爲協程。
import functools
def coroutine(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
generator = function(*args, **kwargs)
next(generator)#調用一次生成器,令生成器對象前進到首個yield表達式。
return generator
return wrapper
#!/usr/bin/env python
# encoding:utf-8
@coroutine
def mouse_handler(successor=None):
while True:
event = (yield)
if 0 < event <= 10:
print("mouse-num: {}".format(event))
elif successor is not None:
successor.send(event)
@coroutine
def key_handler(successor=None):
while True:
event = (yield)
if 10 < event <= 20:
print("key-num: {}".format(event))
elif successor is not None:
successor.send(event)
@coroutine
def timer_handler(successor=None):
while True:
event = (yield)
if 20 < event <= 30:
print("timer-num: {}".format(event))
elif successor is not None:
successor.send(event)
def main():
pipeline = key_handler(mouse_handler(timer_handler()))
events = [2, 5, 14, 22, 18, 3, 35, 27, 20]
for event in events:
pipeline.send(event)
if __name__ == "__main__":
main()