设计模式之责任链模式
责任链模式
概念
Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者
场景
责任链模式主要是按顺序处理一些列请求的时候,将处理函数分离在独立的模块中,再串联成责任链,依次处理的一种设计模式。
如果你编写了一个方法,要处理一个学生毕业这个行为。那么这个学生提交毕业请求后,需要先检查他的成绩是否都合格,接着检查毕业论文是否提交,然后检查导师是否同意毕业,最后检查校领导是否同意毕业。
如果这些检查被封装到一个方法里,这个方法会随着业务的变化,越来越臃肿。责任链模式主要是将每个检查拆解成独立的类,然后按照顺序依次调用。
毕业请求传递到当前类,如果检查成功,就将请求传递给下一个类。如果拒绝请求,就终止这个毕业请求。
责任链模式在很多语言中被广泛应用,并常常结合组合模式使用。例如,在HTML中浏览器事件在冒泡阶段,点击按钮时,先把click事件发送给当前按钮,然后发送给按钮的容器,再发送给容器所在的页面,依次向上传递。
优势
- 请求的处理函数严格按照责任链的顺序执行
- 每个处理类,单一职责
- 新增处理类比较简单
案例
首先为处理类定义接口
public interface IHandler { IHandler SetNext(IHandler handler); object Handle(object request); }
然后编写一批处理类
abstract class AbstractHandler : IHandler { private IHandler _nextHandler; public IHandler SetNext(IHandler handler) { this._nextHandler = handler; // Returning a handler from here will let us link handlers in a // convenient way like this: // monkey.SetNext(squirrel).SetNext(dog); return handler; } public virtual object Handle(object request) { if (this._nextHandler != null) { return this._nextHandler.Handle(request); } else { return null; } } } class MonkeyHandler : AbstractHandler { public override object Handle(object request) { if ((request as string) == "Banana") { return $"Monkey: I'll eat the {request.ToString()}.\n"; } else { return base.Handle(request); } } }
这里为所有处理类,编写了一个基类
class Client { // The client code is usually suited to work with a single handler. In // most cases, it is not even aware that the handler is part of a chain. public static void ClientCode(AbstractHandler handler) { foreach (var food in new List<string> { "Nut", "Banana", "Cup of coffee" }) { Console.WriteLine($"Client: Who wants a {food}?"); var result = handler.Handle(food); if (result != null) { Console.Write($" {result}"); } else { Console.WriteLine($" {food} was left untouched."); } } } }
编写一个类,负责按照顺序调用责任链的每一个Command
实际调用,可以灵活的选择从哪一个类开始调用
// The other part of the client code constructs the actual chain. var monkey = new MonkeyHandler(); var squirrel = new SquirrelHandler(); var dog = new DogHandler(); monkey.SetNext(squirrel).SetNext(dog); // The client should be able to send a request to any handler, not // just the first one in the chain. Console.WriteLine("Chain: Monkey > Squirrel > Dog\n"); Client.ClientCode(monkey); Console.WriteLine(); Console.WriteLine("Subchain: Squirrel > Dog\n"); Client.ClientCode(squirrel);