面向对象编程思想-责任链模式

一、引言

你在公司里请过假吗?员工向管理者发出请求,每个管理者都有可能接收到请求,将这些管理者串成一个链子,直到有处理这个请求为止。目前我们公司请假制度是:2天以内项目经理审批即可,3天以内项目总监参与审批,超过3天的休假必须经过总经理签字批准。这个常见的生活场景就用到了我们今天要学习的内容,责任链模式。

二、责任链模式

定义:使多个对象都有机会处理请求,从而避免请求的发出者和接收者之间的耦合关系。将这个对象链成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

下面是责任链模式结构图:

 

下面是代码demo:

    //抽象处理角色类
    abstract class Handler
    {
        //持有后继的责任角色,并可以设置
        public Handler seccessor;
        public void SetSeccessor(Handler seccessor)
        {
            this.seccessor = seccessor;
        }
        //处理请求
        public abstract void Handle(int request);
    }
    //具体处理类
    class ConcreteHandlerA : Handler
    {
        public override void Handle(int request)
        {
            //判断当前是否可以处理
            if(request < 10)
            {
                Console.WriteLine($"{this.GetType().Name}处理请求{request}");
            }
            //如果不可以,判断是否有后继角色,如果有,交予后继角色处理
            else if(seccessor!=null)
            {
                seccessor.Handle(request);
            }
        }
    }
     class ConcreteHandlerB : Handler
    {
        public override void Handle(int request)
        {
            if (request>10 && request <20)
            {
                Console.WriteLine($"{this.GetType().Name}处理请求{request}");
            }
            else if (seccessor != null)
            {
                seccessor.Handle(request);
            }
        }
    }
     class ConcreteHandlerC:Handler
    {
        public override void Handle(int request)
        {
            if (request > 20 && request<30)
            {
                Console.WriteLine($"{this.GetType().Name}处理请求{request}");
            }
            else if (seccessor != null)
            {
                seccessor.Handle(request);
            }
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            //组织责任链
            ConcreteHandlerA concreteHandlerA = new ConcreteHandlerA();
            ConcreteHandlerB concreteHandlerB = new ConcreteHandlerB();
            ConcreteHandlerC concreteHandlerC = new ConcreteHandlerC();
            concreteHandlerA.SetSeccessor(concreteHandlerB);
            concreteHandlerB.SetSeccessor(concreteHandlerC);
            //接收请求 并处理
            int[] requests = new int[] { 2,7,14,16,25,36};
            foreach (int item in requests)
            {
                concreteHandlerA.Handle(item);
            }
            Console.Read();
        }
    }
View Code

分析:由具体Handler类组成责任链,但链对象并不知道链整体结构,简化对象的相互连接。它们只需要保持下一个后继者的引用,而不需要保持所有候选者的引用,降低了耦合度。可以随时增加或修改一个请求的结构,增加了给对象指派职责的灵活性。

下面是解决开篇的生活例子,代码demo

    //请求类
    class Request
    {
        public double count;
        public string typeName;
        public Request(double count, string typeName)
        {
            this.count = count;
            this.typeName = typeName;
        }
    }
    //审批人
    abstract class Handler
    {
        public Handler nextHandle { get; set; }
        public string name;
        public Handler(string name)
        {
            this.name = name;
        }
        public abstract void Handle(Request request);
    }
     //项目经理
    class ConcreteHandleA : Handler
    {
        public ConcreteHandleA(string name) : base(name)
        {

        }
        public override void Handle(Request request)
        {
            if(request.typeName=="请假" && request.count<2)
            {
                Console.WriteLine($"{name}:{request.typeName}数量为{request.count},被批准");
            }
            else if(nextHandle!=null)
            {
                nextHandle.Handle(request);
            }
        }
    }
      //项目总监
     class ConcreteHandleB:Handler
    {
        public ConcreteHandleB(string name) : base(name)
        {

        }
        public override void Handle(Request request)
        {
            if (request.typeName == "请假" && request.count < 3)
            {
                Console.WriteLine($"{name}:{request.typeName}数量为{request.count},被批准");
            }
            else if (nextHandle != null)
            {
                nextHandle.Handle(request);
            }
        }
    }
    //总经理
    class ConcreteHandleC:Handler
    {
        public ConcreteHandleC(string name) : base(name)
        {

        }
        public override void Handle(Request request)
        {
            if (request.typeName == "请假" && request.count < 5)
            {
                Console.WriteLine($"{name}:{request.typeName}数量为{request.count},被批准");
            }
            else if (request.typeName == "加薪" && request.count < 2000)
            {
                Console.WriteLine($"{name}:{request.typeName}数量为{request.count},被批准");
            }
            else if (request.typeName == "加薪" && request.count > 5000)
            {
                Console.WriteLine($"{name}:{request.typeName}数量为{request.count},我再想想吧");
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //三个不同的请求
            Request requestA = new Request(1, "请假");
            Request requestB = new Request(2, "请假");
            Request requestC = new Request(8000, "加薪");
            //三个管理者
            ConcreteHandleA concreteHandleA = new ConcreteHandleA("项目经理");
            ConcreteHandleB concreteHandleB = new ConcreteHandleB("项目总监");
            ConcreteHandleC concreteHandleC = new ConcreteHandleC("总经理");
            //设置上级审批角色
            concreteHandleA.nextHandle = concreteHandleB;
            concreteHandleB.nextHandle = concreteHandleC;
            //发出请求
            concreteHandleA.Handle(requestA);
            concreteHandleA.Handle(requestB);
            concreteHandleA.Handle(requestC);
            Console.Read();
        }
    }
View Code

分析:不同的请假天数决定不同的审批者,如果把所有的审批者放在一个对象里,显然是破坏“开-闭”原则的,不利于扩展。我们尽可能的封装变化,根据不同的请求,创建多个审批类,每个类负责自己范围内的职责,设置上级审批者,如果不在职责范围交予上级审批,这样也就形成了职责链。

纯的责任链模式:要求一个具体处理者对象只能在两个行为中选择一个,一是承担责任,二是把责任推给下家,不允许出现某一个具体的处理者对象在承担了一部分责任后又把责任推给下家。请求在责任链中必须被处理不能出现无果而终的解决

不纯的责任链模式:一个请求可以最终不被任何接收端对象所接收

优点:

1.降低耦合度。请求接收者和发送者都没有对方明确信息,且链中对象不需要知道链结构

2.职责链可简化对象之间的链接。它仅需要保持一个后继者的引用,而不需要保持它所有候选者的引用

3.增加给对象指派职责的灵活性。可以在运行时刻动态的增加或修改处理一个请求的那些指责

缺点:

1.不能保证请求一定被接收。请求没有明确的接收者,可能到链末端也得不到处理。

2.责任链过长,系统性能可能受到影响;调试起来不方便

适用场景:

1.有多个的对象处理请求,哪个对象处理请求运行时刻自动确定

 2.在不明确接收者的情况下,向多个对象中的一个提交一个请求

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

原文地址:https://www.cnblogs.com/jdzhang/p/7421002.html