责任链模式

简介

Advoid coupling the sender of a reuest to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

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

主要解决

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

优缺点

优点

  • 解耦了请求与处理;
  • 请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一级节点对象;
  • 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;
  • 链路结构灵活,可以通过改变链路结构动态地新增或删减责任;
  • 易于扩展新的请求处理类(节点),符合 开闭原则

缺点

  • 责任链路过长时,可能对请求传递处理效率有影响;
  • 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃;

使用场景

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

使用场景

首先来看下 责任链模式 的通用 UML 类图:

责任链模式

从 UML 类图中,我们可以看到,责任链模式 主要包含两种角色:

  • 抽象处理者(Handler):定义一个请求处理的方法,并维护一个下一个处理节点 Handler 对象的引用;
  • 具体处理者(ConcreteHandler):对请求进行处理,如果不感兴趣,则进行转发;

以下是 责任链模式 的通用代码:

class Client {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        handlerA.setnextHanlder(handlerB);
        handlerA.handleRequest("requestB");
    }

    static abstract class Handler {
        protected Handler mNextHandler;

        public void setnextHanlder(Handler successor) {
            this.mNextHandler = successor;
        }

        public abstract void handleRequest(String request);
    }

    static class ConcreteHandlerA extends Handler {

        @Override
        public void handleRequest(String request) {
            if ("requestA".equals(request)) {
                System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
                return;
            }
            if (this.mNextHandler != null) {
                this.mNextHandler.handleRequest(request);
            }
        }
    }
    static class ConcreteHandlerB extends Handler {

        @Override
        public void handleRequest(String request) {
            if ("requestB".equals(request)) {
                System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
                return;
            }
            if (this.mNextHandler != null) {
                this.mNextHandler.handleRequest(request);
            }
        }
    }
}

上面的代码中,其实我们把消息硬编码为String类型,而真实业务中,消息是具备多样性的,可以是intString或者是自定义类型····因此,我们可以在上面代码中的基础上,将消息类型进行抽象Request,增强了消息的包容性。

责任链模式 的本质是:解耦请求与处理,让请求在处理链中能进行传递与被处理;理解 责任链模式 应当理解的是其模式(道)而不是其具体实现(术),责任链模式 的独到之处是其将节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动了起来。因此,上面的通用代码中,把请求硬编码为String,是为了更加清晰描述 责任链模式 的链式组成与请求传递实现结构原理,而下面内容所要讲述的,其实更多地是基于“术”的层面,如何让 责任链模式 更加完善。

其 UML 类图如下所示:

责任链模式

代码如下所示:

class Client {
    public static void main(String[] args) {
        // 来一个具体处理者A
        Handler<String> handlerA = new ConcreteHandlerA(new ConcreteRequest("requestA"));
        // 来一个具体处理者B
        Handler<String> handlerB = new ConcreteHandlerB(new ConcreteRequest("requestB"));
        // A的下一节点为B
        handlerA.setNextHandler(handlerB);

        // 来一个消息:requestA
        Request<String> request = new ConcreteRequest("requestA");
        // 将消息交由具体处理者A
        handlerA.handleRequest(request);

        System.out.println("------------------------");

        // 来一个消息:requestB
        request = new ConcreteRequest("requestB");
        // 将消息交由具体处理者A
        handlerA.handleRequest(request);

        System.out.println("------------------------");

        // 来一个消息:requestC
        request = new ConcreteRequest("requestC");
        // 将消息交由具体处理者A
        handlerA.handleRequest(request);
    }

    // 抽象消息
    static abstract class Request<T> {
        private T mRequest;

        public Request(T request) {
            this.mRequest = request;
        }

        public T getRequest() {
            return this.mRequest;
        }

        @Override
        public String toString() {
            return this.mRequest.toString();
        }

        public abstract boolean isSame(Request<T> request);
    }

    // 具体消息
    static class ConcreteRequest extends Request<String> {

        public ConcreteRequest(String request) {
            super(request);
        }

        @Override
        public boolean isSame(Request<String> request) {
            return this.getRequest().equals(request.getRequest());
        }
    }

    // 抽象处理者
    static abstract class Handler<T> {
        private Handler<T> mNextHandler;
        private Request<T> mRequest;

        public Handler(Request<T> request) {
            this.mRequest = request;
        }

        public void setNextHandler(Handler<T> successor) {
            this.mNextHandler = successor;
        }

        public final void handleRequest(Request<T> request) {
            do {
                if (this.mRequest.isSame(request)) {
                    this.handle(request);
                    break;
                }
                if (this.mNextHandler != null) {
                    this.mNextHandler.handleRequest(request);
                    break;
                }
                System.out.println("No Handlers can handle this request: " + request);
            } while (false);
        }

        protected abstract void handle(Request<T> request);

    }

    // 具体处理者A
    static class ConcreteHandlerA extends Handler<String> {

        public ConcreteHandlerA(Request<String> request) {
            super(request);
        }

        @Override
        protected void handle(Request<String> request) {
            System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
        }
    }

    // 具体处理者B
    static class ConcreteHandlerB extends Handler<String> {

        public ConcreteHandlerB(Request<String> request) {
            super(request);
        }

        @Override
        protected void handle(Request<String> request) {
            System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
        }
    }
}

运行结果如下:

ConcreteHandlerA deal with request: requestA
------------------------
ConcreteHandlerB deal with request: requestB
------------------------
No Handlers can handler this request: requestC

责任链模式 的本质是解耦请求和处理,上面的代码抽象了请求Request和处理Hanlder,已经很完善了,但是还可以更加完善。因为 责任链模式 具备链式结构,而上面代码中,我们看到,负责组装链式结构的角色是客户端,当链式结构较长时,客户端的工作会非常繁琐,并且客户端代码相对臃肿,且后续更改处理者或消息类型时,都必须在客户端中进行修改,不符合 开闭原则。产生这些问题的原因就是因为链式结构的组装过于复杂,而对于复杂结构的创建,很自然我们就会想到 建造者模式,使用 建造者模式,我们完全可以对客户端指定的处理节点对象进行自动链式组装,客户只需指定处理节点对象,其他任何事情都无需关心,并且客户指定的处理节点对象顺序不同,构造出来的链式结构也随之不同。

具体代码如下:

class Client {
    public static void main(String[] args) {
        Handler.Builder<String> builder = new Handler.Builder<String>();
        List<Handler<String>> handlers = makeHanlders();
        for (Handler<String> handler : handlers) {
            builder.addHandler(handler);
        }
        Handler<String> firstHandler = builder.build();
        for (int i = 0; i < 25; ++i) {
            System.out.println("-----------------");
            Request<String> request = makeRequest(String.format("%03d", i));
            firstHandler.handleRequest(request);
        }
    }

    private static List<Handler<String>> makeHanlders() {
        List<Handler<String>> handlers = new ArrayList<>();
        for (int i = 0; i < 20; ++i) {
            String request = String.format("%03d", i);
            handlers.add(makeHandler("handler" + request, makeRequest(request)));
        }
        return handlers;
    }

    private static Request<String> makeRequest(String request) {
        return new Request<String>(request) {
            @Override
            public boolean isSame(Request<String> request) {
                return this.getRequest().equals(request.getRequest());
            }
        };
    }

    private static Handler<String> makeHandler(final String handlerName, Request<String> request) {
        return new Handler<String>(request) {
            @Override
            protected void handle(Request<String> request) {
                System.out.println(String.format("%s deal with request: %s", handlerName, request));
            }
        };
    }

    // 抽象消息
    static abstract class Request<T> {
        ...
        ...
    }

    // 抽象处理者
    static abstract class Handler<T> {
        ...
        ...
        private void setNextHandler(Handler<T> handler) {
            this.mNextHandler = handler;
        }
        ...
        ...
        public static class Builder<T> {
            private Handler<T> mFirst;
            private Handler<T> mLast;

            public Builder<T> addHandler(Handler<T> handler) {
                do {
                    if (this.mFirst == null) {
                        this.mFirst = this.mLast = handler;
                        break;
                    }
                    this.mLast.setNextHandler(handler);
                    this.mLast = handler;

                } while (false);
                return this;
            }

            public Handler<T> build() {
                return this.mFirst;
            }
        }
    }
}

因为 建造者模式 要构建的是节点处理者,因此我们把Builder作为Handler的静态内部类,并且因为客户端无需进行链式组装,因此我们把链式组装方法setNextHandler设置为private,使Handler更加高内聚。

运行结果如下:

-----------------
handler000 deal with request: 000
-----------------
handler001 deal with request: 001
-----------------
handler002 deal with request: 002
-----------------
handler003 deal with request: 003
-----------------
handler004 deal with request: 004
-----------------
handler005 deal with request: 005
-----------------
handler006 deal with request: 006
-----------------
handler007 deal with request: 007
-----------------
handler008 deal with request: 008
-----------------
handler009 deal with request: 009
-----------------
handler010 deal with request: 010
-----------------
handler011 deal with request: 011
-----------------
handler012 deal with request: 012
-----------------
handler013 deal with request: 013
-----------------
handler014 deal with request: 014
-----------------
handler015 deal with request: 015
-----------------
handler016 deal with request: 016
-----------------
handler017 deal with request: 017
-----------------
handler018 deal with request: 018
-----------------
handler019 deal with request: 019
-----------------
No Handlers can handle this request: 020
-----------------
No Handlers can handle this request: 021
-----------------
No Handlers can handle this request: 022
-----------------
No Handlers can handle this request: 023
-----------------
No Handlers can handle this request: 024

举个例子

例子:小明是一个初级软件开发工程师,假设现在公司有几个需求需要开发,这些需求有些比较容易,有些比较困难。开发团队中有初级工程师,中级工程师,高级工程师和资深工程师,按需求难度进行划分,初级工程师能解决就交由初级工程师,否则将需求转交到更高一级工程师,直到资深工程师。如果资深工程师都无法解决这个需求,则要求产品更改需求。

分析:以上例子是一个典型的 责任链模式 需求,工程师对应节点处理者,需求对应请求。利用 责任链模式,只需将需求一个一个交由初级工程师(小明),需求就会自动地传递给具备相应能力进行开发的工程师手中,或者需求无法解决,则交由产品更改。

具体代码如下:

class Client {
    public static void main(String[] args) {
        Engineer xiaoming = new Engineer.Builder()
            .addEngineer(new JuniorEngineer())
            .addEngineer(new MidEngineer())
            .addEngineer(new SeniorEngineer())
            .addEngineer(new ProfessionalEngineer())
            .build();
        IProject easyProject = new EasyProject();
        IProject normalProject = new NormalProject();
        IProject hardProject = new HardProject();
        IProject tooHardProject = new TooHardProject();
        IProject beyondProject = new BeyondProject();

        if(!xiaoming.doWork(easyProject)){
            System.out.println("tell Product Manager: easy project can not complete");
        }
        if(!xiaoming.doWork(normalProject)){
            System.out.println("tell Product Manager: normal project can not complete");
        }
        if(!xiaoming.doWork(hardProject)){
            System.out.println("tell Product Manager: hard project can not complete");
        }
        if(!xiaoming.doWork(tooHardProject)){
            System.out.println("tell Product Manager: too hard project can not complete");
        }
        if(!xiaoming.doWork(beyondProject)){
            System.out.println("tell Product Manager: beyond project can not complete: "+beyondProject.difficulty());
        }
    }

    interface IProject {
        static int EASY = 0;
        static int NORMAL = 1;
        static int HARD = 2;
        static int TOO_HARD = 3;
        static int BEYOND = 4;

        // 项目难度
        int difficulty();
    }

    static class EasyProject implements IProject{

        @Override
        public int difficulty() {
            return IProject.EASY;
        }
    }
    static class NormalProject implements IProject{

        @Override
        public int difficulty() {
            return IProject.NORMAL;
        }
    }
    static class HardProject implements IProject{

        @Override
        public int difficulty() {
            return IProject.HARD;
        }
    }
    static class TooHardProject implements IProject{

        @Override
        public int difficulty() {
            return IProject.TOO_HARD;
        }
    }

    static class BeyondProject implements IProject{

        @Override
        public int difficulty() {
            return IProject.BEYOND;
        }
    }

    static abstract class Engineer {
        private Engineer mSuccessor;

        public final boolean doWork(IProject project) {
            boolean bRet = false;
            do {
                if (this.filterProject(project)) {
                    bRet = this.writeCode(project);
                    break;
                }
                if (this.mSuccessor != null) {
                    bRet = this.mSuccessor.doWork(project);
                    break;
                }
            } while (false);
            return bRet;
        }

        protected abstract boolean filterProject(IProject project);

        protected abstract boolean writeCode(IProject project);

        public static class Builder {
            private Engineer mFirst;
            private Engineer mLast;

            public Builder addEngineer(Engineer engineer) {
                if (this.mFirst == null) {
                    this.mFirst = this.mLast = engineer;
                } else {
                    this.mLast.mSuccessor = engineer;
                    this.mLast = engineer;
                }
                return this;
            }

            public Engineer build() {
                return this.mFirst;
            }
        }
    }

    // 初级工程师
    static class JuniorEngineer extends Engineer {

        @Override
        protected boolean filterProject(IProject project) {
            return project.difficulty() <= IProject.EASY;
        }

        @Override
        protected boolean writeCode(IProject project) {
            System.out.println("Junior engineer completes project: " + project.difficulty());
            return true;
        }
    }

    // 中级工程师
    static class MidEngineer extends Engineer {

        @Override
        protected boolean filterProject(IProject project) {
            return project.difficulty() <= IProject.NORMAL;
        }

        @Override
        protected boolean writeCode(IProject project) {
            System.out.println("Middle level engineer completes project: " + project.difficulty());
            return true;
        }
    }

    // 高级工程师
    static class SeniorEngineer extends Engineer {

        @Override
        protected boolean filterProject(IProject project) {
            return project.difficulty() <= IProject.HARD;
        }

        @Override
        protected boolean writeCode(IProject project) {
            System.out.println("Senior engineer completes project: " + project.difficulty());
            return true;
        }
    }

    // 资深工程师
    static class ProfessionalEngineer extends Engineer {

        @Override
        protected boolean filterProject(IProject project) {
            return project.difficulty() <= IProject.TOO_HARD;
        }

        @Override
        protected boolean writeCode(IProject project) {
            System.out.println("Professional engineer completes project: " + project.difficulty());
            return true;
        }
    }
}

结果如下:

Junior engineer completes project: 0
Middle level engineer completes project: 1
Senior engineer completes project: 2
Professional engineer completes project: 3
tell Product Manager: beyond project can not complete: 4
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,302评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,563评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,433评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,628评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,467评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,354评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,777评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,419评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,725评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,768评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,543评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,387评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,794评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,032评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,305评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,741评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,946评论 2 336

推荐阅读更多精彩内容