设计模式之责任链模式

责任链模式

概念

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);
posted @ 2022-10-06 11:33  内心澎湃的水晶侠  阅读(46)  评论(0编辑  收藏  举报