Java 设计模式 -- 职责链模式

下面,将通过一个例子,对职责链模式进行介绍。

问题:设想,你有一个呼叫中心,员工分成三个层级,接线员,主管和经理。客户来电时会先分配给接线员,若接线员处理不了,就必须将来电往上转给主管,若主管无法处理,将来电往上转给经理。请设计这个问题的类和数据结构(为了方便,将呼叫者的问题分等级,分别为 S 级,由接线员处理,SS 级,由主管处理,SSS级,由经理处理)。


首先,分析一下这个问题,对于一次电话呼叫,肯定存在 呼叫人和被呼叫人,所以我们可能需要设计一个 Call 类来表示一个电话呼叫,一个 Caller 类用于封装呼叫人的属性,Employee 类用于表示接听人,因为员工分三种,所以我们需要将 Employee 定义为一个抽象类,用于封装员工的共同属性。既然各个类模型已经想好了,那么就要想想如何设计方法呢?也就是如何实现电话的传递呢?想想 Java 中是如何模仿指针效果的?下面来看看实现

public class Caller {

    private String mName;
    private String mRank;

    public Caller(String rank) {
        this.mRank = rank;
    }

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        this.mName = name;
    }

    public String getRank() {
        return mRank;
    }

    public void setRank(String rank) {
        mRank = rank;
    }

    public void disconnect() {
        System.out.println("Caller : disconnect");
    }

}

以上为 Caller 方法,只有一个带问题等级参数的构造函数,用于表示呼叫者必须首先声明自己问题的等级。还有一个 disconnect() 方法,当呼叫者问题被处理完毕后调用,表示挂掉电话。

public abstract class Employee {

    protected Employee mBoss;

    public abstract void setBoss(Employee boss);

    public abstract void handleCall(Call call);

}

以上是一个抽象类,定义了一个属性和两个方法, setBoss() 用于设置当前员工的顶头上司,handleCall() 方法在员工接听电话时调用。下面来看看 接线员类的实现

public class Respondent extends Employee {

    @Override
    public void handleCall(Call call) {
        if (call.getCaller().getRank().equals("S")) {
            System.out.println("Respondent : handle this call");
            call.getCaller().disconnect();
        } else {
            mBoss.handleCall(call);
        }
    }

    @Override
    public void setBoss(Employee boss) {
        mBoss = boss;
    }

}

以上实现表明,setBoss() 方法必须在 handleCall() 方法之前调用,否则会报空指针错误,因为在 handleCall() 方法逻辑中,我们设置了,如果该员工能处理指定信息,则进行处理,处理完之后呼叫者挂断电话。如果不能处理,就将该呼叫传递给自己的顶头上司,交给他去处理。需要注意的是对于 Manager 类的实现,由于它已经没有上司,所以在handleCall()方法中做特殊处理,如下所示

@Override
    public void handleCall(Call call) {
        if (call.getCaller().getRank().equals("SSS")) {
            System.out.println("Manager :  handle this call");
            call.getCaller().disconnect();
        } else {
            System.out.println("We can not handle this call");
        }
    }

这里如果经理也处理不了该通话,只能打印不能处理该问题,不能再往上传递,否则会报空指针错误。

下面来看看 Call 类是如何实现的

public class Call {

    private Caller mCaller;
    private Employee mEmployee;

    public Call(Caller caller) {
        this.mCaller = caller;
    }

    public Caller getCaller() {
        return mCaller;
    }

    public void handle() {
        mEmployee.handleCall(this);
    }

    public void setRespondent(Employee respondent) {
        mEmployee = respondent;
    }

}

在这里,我们有一个 setRespondent() 方法,这里设置的员工是接线员,因为只有这样才可以确保如果该通话无法被处理向上传递。看到这里,感觉这种模式就像踢皮球一样,你踢给我,我踢给你,当然也可以这么形容,这种模式的实现思想和指针类似。

其实,我们已经在很多地方见到过这种模式,比如说 Java 的异常机制,如果一个地方抛出了异常,会首先寻找距离最近的 catch 语句,如果可以处理,就处理,不可以处理,就再往上抛,直到可以被处理为止。

再比如说 Android 当中的触摸事件,也是从容器中一级一级向下传,直到传到最底层的 View 视图,当然传到其中的任何一个容器的时候,都可以截断这种传递。

我所理解的职责链模式就是如此,如果有什么错误的地方,希望予以指正,互相学习。

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

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,577评论 18 399
  • 每日目标今日完成: 早课听书学习,读书笔记,英语口语练习,普通话声音复习训练,演讲练习,作品创作,教学(下午)。 ...
    微风淡月88郑亚儿阅读 157评论 0 0
  • 我在雨中看你, 不远不近, 如叶片低眉的水滴, 触手可及又迅速溜去, 掉入一团朦胧的雾气, 打湿眼眶萦绕不去, 我...
    甜橙可宜阅读 260评论 4 3
  • 真不知用什么语言来表达黄河的雄伟壮观,只站在川上感叹,黄河之水天上来 奔流到海不复回……
    pan123456阅读 474评论 0 0