责任链模式(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()