10、Android设计模式---(使编程更有灵活性)责任链模式

一、介绍,定义

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

二、使用场景

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

三、UML类图

12.png
13.png

客户端发出请求,调用抽象类Handler中的方法处理逻辑业务。对象ConcreteHandler1与ConcreteHandler2继承Handler,其中ConcreteHandler1中持有下一个节点ConcreteHandler2的引用;事件由1对象发出,如果其处理不了,则交由2对象处理! 这是简单的责任链模式结构图,下面使用代码的方式展现:

四、通用模板

抽象处理者

public abstract class Handler {
    //下一代处理者
    public Handler nextProcessor;
    // 每一个实现类处理
    public abstract void handleRequest(String msg);
}

具体处理者

public class Processor1 extends Handler {
    @Override
    public void handleRequest(String msg) {
        if(msg.equals("Processor1")) {
            System.out.println("第一个处理者处理");
        } else {
            nextProcessor.handleRequest(msg);
        }
    }
}

public class Processor2 extends Handler {
    @Override
    public void handleRequest(String msg) {
        if(msg.equals("Processor2")) {
            System.out.println("第二个处理者处理");
        } else {
            nextProcessor.handleRequest(msg);
        }
    }
}

客户类

public class Client{
    public static void main(String[] args) {
        Processor1 processor1 = new Processor1();
        Processor2 processor2 = new Processor2();

        processor1.nextProcessor = processor2;
        processor2.nextProcessor = processor1;

        processor1.handleRequest("Processor2");
    }
}

这只是一个简化版通用模式代码,大多数情况下,要将请求的规则和请求同时进行封装(这里只判断了字符串)

五、简单实现

小民去国外学习花了近10万块,于是找公司报销,向组长申请报销费用,组长一看这么大一笔钱,他哪里有这个权限,他手里最多才可以批1000块,于是组长就拿着票据去找部门主管,主管一看要报这么多钱,自己权限内只能批1万以下的费用,这完全超出了自己的权限范围呀,于是又只得去找上一级也就是经理,经理一看,我也只能批5万以下的费用啊。于是二话不说拿着票据直接奔向了老板的办公室,让老板去处理这个请求。
小民从链的底端开始发出一个申请报账的请求,首先由组长处理该请求,组长比对后发现自己权限不够,于是将该请求转发给位于该链中下一个节点的主管,主管比对后发现自己权限也不够,又只能将该请求转发给经理,而经理同样权限不够,毕竟10万块的大数目只有老板能处理,于是最后经理又将请求转发给了老板,这样层层转达直到请求被处理。
从中大家可以看到一个显而易见的事,就是至始至终小民只与组长产生了关联,后面具体由谁处理报销的票据,小民并不关心,只关心自己的票据(请求)有没有被成功处理。责任链模式在这里很好的将请求的发起者和处理者解耦。接下来我们用代码来实现这一过程。

public abstract class Leader {
    protected Leader nextHandler;//上一级领导(处理者),UML图中的successor
    /**
     * 处理报账请求
     * @param money 报账额度
     *  申明为final,子类无法重写
     */
    public final void handleRequest(double money){
        if(money<=limit()){
            handle(money);
        }else{
            if(null!=nextHandler){//有上一级处理者
                nextHandler.handleRequest(money);
            }else{
                Log.e(getClass().getSimpleName(),"没有领导能批复你的票据报销啦,自己去报销吧!");
            }
        }
    }

    /**
     * 自身能批复的报账额度
     * @return 额度
     */
    public abstract double limit();

    /**
     * 处理报账行为
     * @param money 报账额度
     */
    public abstract void handle(double money);
}

在这个抽象的领导类中只做了两件事,一是定义了两个抽象接口方法来确定一个领导者应有的行为和属性,二是声明了一个处理报账请求的方法来确定当前领导是否有能力处理报账请求,如果没有这权限,则将该请求转发给上级领导处理。接下来是各个具体的领导类的实现。
具体领导者,继承自抽象领导者类

//组长
public class GroupLeader extends Leader {
    @Override
    public double limit() {
        return 1000;
    }
    @Override
    public void handle(double money) {
        Log.e(getClass().getSimpleName(),"组长批复报销了你的"+money+"元");
    }
}

//主管
public class Director extends Leader {
    @Override
    public double limit() {
        return 10000;
    }
    @Override
    public void handle(double money) {
        Log.e(getClass().getSimpleName(),"主管批复报销了你的"+money+"元");
    }
}

//经理
public class Manager extends Leader {
    @Override
    public double limit() {
        return 50000;
    }
    @Override
    public void handle(double money) {
        Log.e(getClass().getSimpleName(),"经理批复报销了你的"+money+"元");
    }
}

//BOSS
public class Boss extends Leader {
    @Override
    public double limit() {
        return 999999;
    }
    @Override
    public void handle(double money) {
        Log.e(getClass().getSimpleName(),"老板批复报销了你的"+money+"元");
    }
}

具体领导类创建后,从组长开始发起请求申请报账

public class XiaoMin {
    public static void main(String[] args){
    protected void init() {
          GroupLeader groupLeader = new GroupLeader();
          Director director = new Director();
          Manager manager = new Manager();
          Boss boss = new Boss();

          //设置上一级领导(处理者)对象
          groupLeader.nextHandler = director;
          director.nextHandler = manager;
          manager.nextHandler = boss;

          //发起报账申请
          groupLeader.handleRequest(100000);
        }
    }
}

可以看到最后是BOSS处理了小民的报账申请,而且也只有BOSS才有这个权限处理,但是这里小民在申请的时候却只和组长进行了交流,降低了耦合度,这也是责任链模式的优点。当然这里我们代码也可以直接越过组长找主管或者经理或者直接找BOSS报账也是可以的,这也是责任链模式的灵活之处,请求的发起可以从责任链的任何一个节点开始,同时也可以改变责任链内部传递的规则,如主管不在,我们完全可以跨过主管直接将请求转送给经理。

六、模式的优缺点:

优点

  1. 降低耦合度:客户端不需要知道请求由哪个处理者处理,而处理者也不需要知道处理者之间的传递关系,由系统灵活的组织和分配。
  2. 良好的扩展性:增加处理者的实现很简单,只需重写处理请求业务逻辑的方法。
    缺点
  3. 请求会从链头发出,直到有处理者响应,在责任链比较长的时候会影响系统性能。
  4. 请求递归,调试排错比较麻烦。

七、总结

对于责任链中的一个处理者对象,其只有两个行为,一是处理请求,二是将请求转送给下一个节点,不允许某个处理者对象在处理了请求后又将请求转送给上一级节点的情况。对于一条责任链来说,一个请求最终只有两种情况,一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称该责任链为纯的责任链,对于后一种情况我们称为不纯的责任链,在实际应用中,我们所见到的责任链模式大多为不纯的责任链。

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