三国演义:责任链模式

单例模式

模板方法模式

装饰器模式

门面模式

策略模式

委派模式

故事

前两天,没事又刷了一遍三国演义,看到关羽身在曹营心在汉,听说刘备在袁绍那里,然后就上演了“过五关,斩六将”。

关羽过五关斩六将主要内容:

  • 第一关,东岭关,斩守将孔秀。

    东岭关,守关将名叫孔秀,本是黄巾余党,归降曹操之后,带着五百人奉命防守东岭关。关羽车队从关前通过时,孔秀索要通关文牒,与关羽发生冲突,只一个回合,就被关羽斩杀。

  • 第二关,洛阳关,孟坦和韩福。

    关羽过了东岭关,在要过洛阳时,韩福、孟坦用鹿角拦住道路。先是孟坦挑战,与关羽说翻,交手不敌,孟坦拨马回跑,引关公来追,这样韩福就可以在后面射箭擒拿关公,可谁想到关公赤兔马快,从后面赶上孟坦,一刀就把孟坦给劈了。韩福慌得射了一箭,中关公左臂,关公忍住箭伤,也冲过鹿角,一刀斩杀韩福,于是过洛阳。

  • 第三关,汜水关,卞喜。

    在得知关羽过关斩将,东岭关孔秀、洛阳韩福、孟坦都被杀害,卞喜自思难以抵挡关公。于是就假意迎接关公,在镇国寺安排下刀斧手,准备伺机杀死关公。幸亏有镇国寺老方丈普净给警示,关公这才察觉出阴谋,与卞喜闹翻,一刀斩杀卞喜,于是关公过汜水关。

  • 第四关,王植。

    这王植是韩福的亲家,听说韩福被关公杀死,十分愤怒,于是就要为韩福报仇。在关公到达荥阳时,王植在馆驿设宴,宴请关公和二位皇嫂。却是暗中派从事胡班放火,想要烧死关公。但胡班因关公给父亲胡华带信的缘故,向关羽告了密。关羽和二位皇嫂得以提前逃离馆驿,胡班却假意放火,迷惑王植。不过王植后来察觉,杀了胡班,来追关羽时,被关羽斩杀,于是关公过荥阳。

  • 第五关,黄河渡口,秦琪。

    这秦琪不仅是夏侯惇的爱将,更是老将军蔡阳的外甥,奉命守卫黄河渡口,盘查过往船只。关公到黄河渡口时,要找船只渡河,被秦琪拦住,秦琪不仅不放关公等人渡河,反而口出狂言,终于激怒关公,被关公斩杀

这就是关羽过五关斩六将的全部过程。

这个故事情节让我想起了一个设计模式:责任链模式

其实,我们生活中也有着非常多的责任链模式。比如:基本上每个公司都有自己的OA系统,主要是员工基本信息、请假、调休、报销等功能。如果,我有事需要请假两天,于是登录OA系统,发起请假审批。

由于,对于请假时间的长短公司有如下规定:

小于等于半天,审批环节:项目负责人

大于半天,小于等于1天的,审批环节:项目负责人+技术总监

超过1天,审批环节:项目负责人+技术总监+Boss

可以看得出来,我请假审批流程为项目负责人+技术总监+Boss。

到底什么是责任链设计模式?

什么是责任链模式呢

责任链模式英文解释为:

Avoid coupling the sender of a request to its receiver bygiving more than one object a chance to handle the request.Chainthe receiving objects and pass the request along the chain until anobject handles it.

责任链模式(Chain of Responsibility Pattern)将链中每一个节点都看作一个对象,每个节点处理的请求均不同,且内部自动维护下一个节点对象。当一个请求从链式的首端发出时,会沿着责任链预设的路径依次传递到每一个节点对象,直至被链中的某个对象处理为止,属于行为型设计模式

责任链模式通用代码

Java实现责任链设计模式如下:

public abstract class Handler {
        protected Handler nextHandler = null;
        public abstract void handle();
        public Handler getNextHandler() {
            return nextHandler;
        }
        public void setNextHandler(Handler nextHandler) {
            this.nextHandler = nextHandler;
        }
}

public class HandlerA extends Handler{
        @Override
        public void handle() {
            if(nextHandler == null){
                System.out.println("HandlerA handle ...");
            }else{
                nextHandler.handle();
            }
        }
}

public class HandlerB extends Handler{
        @Override
        public void handle() {
            if(nextHandler == null){
                System.out.println("HandlerB handle ...");
            }else{
                nextHandler.handle();
            }
        }
}

public class HandlerC extends Handler{
    @Override
    public void handle() {
        if(getNextHandler() == null){
            System.out.println("HandlerC handle ...");
        }else{
            getNextHandler().handle();
        }
    }
}
//测试
public class  Client{
    public static void main(String[] args) {
        Handler handlerA = new HandlerA();
        Handler handlerB = new HandlerB();
        handlerA.setNextHandler(handlerB);
        handlerA.handle();
    }
}

运行结果:

HandlerC handle ...

从上面代码,我们可以画出UML图:

从UML图中,我们又可以看出,责任链模式中有两个非常重要的角色:

(1)、抽象处理者角色(Handler)

定义处理请求的接口。接口可以也可以给出一个方法以设定和返回对下个对象引用。这个角色通常由一个Java抽象类或者Java接口实现。

(2)、具体处理者角色(HandlerA、HandlerB、HandlerC)

具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下个对象。由于具体处理者持有对下家的引用。

责任链模式的优缺点

  • 优点:请求和处理分开,两者解耦,提供系统的灵活性。
  • 缺点:性能能问,一个链非常长的时候,非常耗时。因为我们避免建立很长的链。

生活中的案例

在日常生活中,责任链模式是比较常见的。我们平时处理工作中的一些事务,往往是各部门协同合作来完成某一个任务的。而每个部门都有各自的职责,因此,很多时候事情完成一半,便会转交到下一个部门,直到所有部门都审批通过,事情才能完成。

责任链模式主要解耦了请求与处理,客户只需将请求发送到链上即可,不需要关心请求的具体内容和处理细节,请求会自动进行传递,直至有节点对象进行处理。

责任链模式主要适用于以下应用场景:

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
  • 在不明确指定接收者的情况下,向多个对象中的一个提交请求。
  • 可动态指定一组对象处理请求。

请假流程的代码实现

下面我们来对,前面的案例:OA上请假流程做一个Java代码的实现。

抽象处理者:领导类

public abstract class Leader {
    private Leader next;
    public void setNext(Leader next) {
        this.next = next;
    }
    public Leader getNext() {
        return next;
    }
    //处理请求的方法
    public abstract void handleRequest(double LeaveDays);
}

项目负责人

public class ProjectLeader extends Leader {
    @Override
    public void handleRequest(double LeaveDays) {
        if (LeaveDays <= 0.5) {
            System.out.println("项目负责人批准您请假" + LeaveDays + "天。");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(LeaveDays);
            } else {
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}

技术总监

public class TechnicalDirectorLeader extends Leader {

@Override
    public void handleRequest(double LeaveDays) {
        if (LeaveDays <= 1) {
            System.out.println("技术总监批准您请假" + LeaveDays + "天。");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(LeaveDays);
            } else {
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}

Boss

public class BossLeader extends Leader {
    @Override
    public void handleRequest(double LeaveDays) {
        if (LeaveDays >= 2 && LeaveDays <= 30) {
            System.out.println("Boss批准您请假" + LeaveDays + "天。");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(LeaveDays);
            } else {
                System.out.println("请假天数太多,没有人批准该假条!");
            }
        }
    }
}

发起审批

public class LeaveApproval {
    public static void main(String[] args) {
        //组装责任链
        Leader projectLeader = new ProjectLeader();
        Leader technicalDirectorLeader = new TechnicalDirectorLeader();
        Leader bossLeader = new BossLeader();

projectLeader.setNext(technicalDirectorLeader);
        technicalDirectorLeader.setNext(bossLeader);

//请假两天,提交请假流程,开启审批环节,
        projectLeader.handleRequest(2);
    }
}

审批结果

Boss批准您请假2.0天。

如果请假天数是31天,审批结果

请假天数太多,没有人批准该假条!

整个请假流程为:

把这张流程图改成纵向:

就这么一环套一环的,使用上面两个例子和两张图来理解责任链模式是不是就更轻松了?

自己吹牛逼,没什么用,下面来看看大神们是怎么使用责任链模式的。

大佬们是如何使用的

在Spring、Mybatis等框架中,都用使用到责任链模式,下面先来看在Spring中是如何使用的。

在Spring MVC中的org.springframework.web.servlet.DispatcherServlet类中:

getHandler 方法的处理使用到了责任链模式,handlerMappings是之前 Spring 容器初始化好的,通过遍历 handlerMappings查找与request匹配的 Handler, 这里返回 HandlerExecutionChain 对象。这个 HandlerExecutionChain对象到后面执行的时候再分析为什么返回的是这样一个对象。

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
 if (this.handlerMappings != null) {
  for (HandlerMapping mapping : this.handlerMappings) {
   HandlerExecutionChain handler = mapping.getHandler(request);
   if (handler != null) {
    return handler;
   }
  }
 }
 return null;
}

以上便是责任链模式在Spring的具体使用,关于Mybatis中责任链模式的使用,请看这篇文章:

建议收藏,mybatis插件原理详解

总结

本文通过关二爷的过五关斩六将和OA系统中的请假审批流程,完美的解释了责任链设计模式。

最后用一句话来总结责任链模式:

各人自扫门前雪,莫管他人瓦上霜。

好了,今天的分享就到此结束,希望你能彻底掌握责任链模式,如果有疑问、想技术探讨、需要学习资源等,请加我微信。

(0)

相关推荐

  • 设计模式(七)——适配器模式(SpringMVC框架分析)

    适配器模式1 现实生活中的适配器例子泰国插座用的是两孔的(欧标),可以买个多功能转换插头 (适配器) ,这样就可以使用了. 2 基本介绍1) 适配器模式(Adapter Pattern)将某个类的接口 ...

  • 【5/25】责任链模式(Chain of Responsibility Pattern)

    这是<小游戏从0到1设计模式重构>系列内容第5篇,所有源码及资料在"程序员LIYI"公号回复"小游戏从0到1"获取. 这一小节我们尝试应用责任链模式 ...

  • PHP设计模式之责任链模式

    PHP设计模式之责任链模式 责任链模式,属于对象行为型的设计模式. Gof类图及解释 GoF定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这 ...

  • [PHP小课堂]PHP设计模式之责任链模式

    [PHP小课堂]PHP设计模式之责任链模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 责任链模式

    一.责任链模式介绍 1.定义与类型 为请求创建一个接收此次请求对象的链 类型:行为型 2.适用场景 一个请求的处理需要多个对象当中的一个或几个协作处理 3.优点 请求的发送者和接收者(请求的处理)解耦 ...

  • 通俗易懂系列 | 设计模式(六):责任链模式

    责任链设计模式是行为设计模式之一. 责任链模式用于在软件设计中实现松散耦合,其中来自客户端的请求被传递到对象链以处理它们.然后链中的对象将自己决定谁将处理请求以及是否需要将请求发送到链中的下一个对象. ...

  • 设计模式之责任链模式

    设计模式之责任链模式

  • 责任链设计模式案例详解,看这一篇就够了

    老哥哔哔哔 责任链设计模式在日常工作中很常见,也很重要,很多开源框架都采用了责任链设计模式,比如:servlet中的Filter.Dubbo中的Filter.Mybatis中的Plugin.sprin ...

  • 崔日明:中国嵌入亚太价值链模式与中国角色变迁之路

    作为全球经济最有活力、对全球经贸增长的贡献超过2/ 3 的地区,毫无疑问,亚太地区已成为全球经贸中心,21 世纪将是亚太地区的世纪。在全球价值链已成为全球经贸合作主要形式的背景下,20 世纪90 年代 ...

  • Chain of Responsibility 职责链模式

    >>返回<C#常用设计模式> 1. 简介 2. 示例 1. 简介 定义 很多对象由每一个对象对其下家的引用而连接起来形成一条链. 请求在这个链上传递,直到链上的某一个对象决定处 ...