责任链与协程实现问题:修改后请求未正确流转
责任链与协程练习题问题排查与修复
问题描述
备考责任链与协程练习题时,编写Python代码遇到以下问题:Handler_gt9处理大于9的请求时会生成新请求,但新请求被直接传给后继的DefaultHandler,而非从责任链起始节点(Handler_04)重新流转,导致无法被对应处理器正确处理(例如修改后的[3,7]本应被Handler_04处理,却直接进入了DefaultHandler)。已知Client类及后续初始化代码不可修改,需排查问题原因并修复。
原代码
import functools def coroutine(function): @functools.wraps(function) def wrapper(*args, **kwargs): generator = function(*args, **kwargs) next(generator) return generator return wrapper @coroutine def DefaultHandler(successor=None): while True: request = yield if any(isinstance(x, str) for x in request) or request[0] < 0 or len(request) != 2: print(f"Request {request} handled by Default_Handler: it was not possible to handle the request {request}") else: if successor is not None: successor.send(request) @coroutine def Handler_04(successor=None): while True: request = yield if isinstance(request[0], (int, float)) and 0 <= request[0] <= 4 and len(request) == 2: print(f"Request {request} handled by Handler_04") else: if successor is not None: successor.send(request) @coroutine def Handler_59(successor=None): while True: request = yield if isinstance(request[0], (int, float)) and 5 <= request[0] <= 9 and len(request) == 2: print(f"Request {request} handled by Handler_59") else: if successor is not None: successor.send(request) @coroutine def Handler_gt9(successor=None): while True: request = yield if isinstance(request[0], (int, float)) and request[0] > 9 and len(request) == 2: print( f"Message from Handler_gt9: it was not possible to handle the request {request}. Request modified") new_data = [request[0] - request[1], request[1]] if successor is not None: successor.send(new_data) else: if successor is not None: successor.send(request) class Client: def __init__(self): self.handler = Handler_04(Handler_59(Handler_gt9(DefaultHandler(None)))) def delegate(self, requests): for request in requests: self.handler.send(request) # Create a client object client = Client() # Create richieste to be processed. requests = [] for i in range(0, 15, 2): requests.append([i, 7]) requests.append([-3, 4]) requests.append(["a", 2]) requests.append([1, 2, 4]) client.delegate(requests)
问题原因
当前责任链的每个处理器仅持有自身后继处理器的引用,没有保存责任链起始节点(Handler_04)的引用。当Handler_gt9生成新请求后,调用successor.send(new_data)会直接将请求传给自己的后继(DefaultHandler),跳过了前面的Handler_04和Handler_59,导致新请求无法被匹配的处理器识别处理。
修复方案
通过全局变量保存责任链起始节点的引用,让Handler_gt9能将新请求发送回链头重新流转,无需修改Client类及后续代码:
- 定义全局变量
chain_head,用于存储链头(Handler_04)的引用; - 在Handler_04中,首次接收请求时将自身引用存入全局变量;
- 修改Handler_gt9的逻辑,生成新请求后不再传给后继,而是通过全局变量将请求发送回链头。
修改后的完整代码:
import functools # 全局变量保存责任链起始节点引用 chain_head = None def coroutine(function): @functools.wraps(function) def wrapper(*args, **kwargs): generator = function(*args, **kwargs) next(generator) return generator return wrapper @coroutine def DefaultHandler(successor=None): while True: request = yield if any(isinstance(x, str) for x in request) or request[0] < 0 or len(request) != 2: print(f"Request {request} handled by Default_Handler: it was not possible to handle the request {request}") else: if successor is not None: successor.send(request) @coroutine def Handler_04(successor=None): global chain_head while True: request = yield # 首次接收请求时,将自身设为链头 if chain_head is None: chain_head = (yield) if isinstance(request[0], (int, float)) and 0 <= request[0] <= 4 and len(request) == 2: print(f"Request {request} handled by Handler_04") else: if successor is not None: successor.send(request) @coroutine def Handler_59(successor=None): while True: request = yield if isinstance(request[0], (int, float)) and 5 <= request[0] <= 9 and len(request) == 2: print(f"Request {request} handled by Handler_59") else: if successor is not None: successor.send(request) @coroutine def Handler_gt9(successor=None): global chain_head while True: request = yield if isinstance(request[0], (int, float)) and request[0] > 9 and len(request) == 2: print( f"Message from Handler_gt9: it was not possible to handle the request {request}. Request modified") new_data = [request[0] - request[1], request[1]] # 将新请求发送回链头重新处理 if chain_head is not None: chain_head.send(new_data) elif successor is not None: successor.send(new_data) else: if successor is not None: successor.send(request) class Client: def __init__(self): self.handler = Handler_04(Handler_59(Handler_gt9(DefaultHandler(None)))) def delegate(self, requests): for request in requests: self.handler.send(request) # Create a client object client = Client() # Create richieste to be processed. requests = [] for i in range(0, 15, 2): requests.append([i, 7]) requests.append([-3, 4]) requests.append(["a", 2]) requests.append([1, 2, 4]) client.delegate(requests)
效果验证
修改后,Handler_gt9生成的新请求会从链头Handler_04重新进入责任链流转:
- 例如请求
[11,7]会被Handler_gt9修改为[4,7],随后发送回Handler_04,最终被Handler_04处理并输出Request [4, 7] handled by Handler_04; - 请求
[13,7]修改为[6,7]后,会被Handler_59处理并输出Request [6, 7] handled by Handler_59。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

