Chain of Resposibility(职责链)
动机(Motivation)
- 让多个对象来处理单个请求
- 预先不知道应该由哪个对象(来自某个对象链)来处理某个特定请求时。
模式定义
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
——《设计模式》GoF
要点总结
- 原则如下所示。
(1) 存在一个对象链(链表、树或任何其他便捷的数据结构)。
(2) 我们一开始将请求发送给链中的第一个对象。
(3) 对象决定其是否要处理该请求。
(4) 对象将请求转发给下一个对象。
(5) 重复该过程,直到到达链尾。 - 客户端代码仅知道第一个处理元素,而非拥有对所有处理元素的引用;并且每个处理 元素仅知道其直接的下一个邻居(称为后继),而不知道所有其他处理元素。这通常是一种单向关系,用编程术语来说是一个单向链表。
- 职责链一定程度上可以用单向链表来代替,现在用的较少。
例子
# -*- coding:utf-8 -*-
class ChainType(object):
Success_To_Next = 0 # 当前节点执行成功后传递到下一个
Fail_To_Next = 1 # 当前节点执行失败后传递到下一个
To_Next = 2 # 直接传递给下一个
class Event(object):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Widget(object):
def __init__(self):
self.next_chain = None
def handle(self, event, handle_type=ChainType.To_Next):
flag = self.process_event(event)
if (handle_type == ChainType.Success_To_Next and flag) or \
(handle_type == ChainType.Fail_To_Next and not flag) or \
handle_type == ChainType.To_Next:
if self.next_chain:
print('cur_chain:%s finish, next chain:%s start' % (self.__class__.__name__, self.next_chain.__class__.__name__))
self.next_chain.handle(event, handle_type)
def process_event(self, event):
handler = 'handle_{}'.format(event)
print('%s start process event:%s' % (self.__class__.__name__, handler))
flag = True
if hasattr(self, handler):
# 对象有该event接口直接执行
method = getattr(self, handler)
method(event)
elif hasattr(self, 'handle_default'):
# 否则该对象有handle_default接口
self.handle_default(event)
else:
# 否则不执行
print('%s process failed, abandon it' % self.__class__.__name__)
flag = False
return flag
def set_next_chain(self, next_chain):
self.next_chain = next_chain
class MainWindow(Widget):
def handle_close(self, event):
print('MainWindow: {}'.format(event))
class SendDialog(Widget):
def handle_paint(self, event):
print('SendDialog: {}'.format(event))
class MsgText(Widget):
def handle_down(self, event):
print('MsgText: {}'.format(event))
def handle_default(self, event):
print('MsgText Default: {}'.format(event))
def main():
main_window = MainWindow()
send_dialog = SendDialog()
msg_text = MsgText()
main_window.set_next_chain(send_dialog)
send_dialog.set_next_chain(msg_text)
for e in ('down', 'paint', 'close'):
print('-' * 20)
evt = Event(e)
main_window.handle(evt, handle_type=ChainType.Fail_To_Next)
if __name__ == '__main__':
main()
- 类型为
ChainType.Fail_To_Next
, 即当前节点处理失败后才发送给下一个节点。输出为
--------------------
MainWindow start process event:handle_down
MainWindow process failed, abandon it
cur_chain:MainWindow finish, next chain:SendDialog start
SendDialog start process event:handle_down
SendDialog process failed, abandon it
cur_chain:SendDialog finish, next chain:MsgText start
MsgText start process event:handle_down
MsgText: down
--------------------
MainWindow start process event:handle_paint
MainWindow process failed, abandon it
cur_chain:MainWindow finish, next chain:SendDialog start
SendDialog start process event:handle_paint
SendDialog: paint
--------------------
MainWindow start process event:handle_close
MainWindow: close
- 类型为
ChainType.To_Next
, 即当前节点处理成功与否都发送给下一个节点。输出为
MainWindow start process event:handle_down
MainWindow process failed, abandon it
cur_chain:MainWindow finish, next chain:SendDialog start
SendDialog start process event:handle_down
SendDialog process failed, abandon it
cur_chain:SendDialog finish, next chain:MsgText start
MsgText start process event:handle_down
MsgText: down
--------------------
MainWindow start process event:handle_paint
MainWindow process failed, abandon it
cur_chain:MainWindow finish, next chain:SendDialog start
SendDialog start process event:handle_paint
SendDialog: paint
cur_chain:SendDialog finish, next chain:MsgText start
MsgText start process event:handle_paint
MsgText Default: paint
--------------------
MainWindow start process event:handle_close
MainWindow: close
cur_chain:MainWindow finish, next chain:SendDialog start
SendDialog start process event:handle_close
SendDialog process failed, abandon it
cur_chain:SendDialog finish, next chain:MsgText start
MsgText start process event:handle_close
MsgText Default: close
网友评论