Android设计模式—责任链模式

1.责任链模式

责任链模式是一种行为型设计模式。它允许将请求沿着处理者链进行发送,收到请求后,每个处理者均可对请求进行处理或将其传递给链上的下一个处理者。这样就避免了请求的发送者和接收者直接的耦合关系。

责任链是由一个个负有一定责任的单元形成一个链条,在这个链条上,每个责任单元都负责自己应该负责的责任,而责任单元之间互不干扰。简单说就是一个请求有多个对象来处理,这些对象是一条链,但具体由哪个对象处理需要根据条件判断来确定,如果不能处理会传递给该链中的下一个对象,直到有对象处理它为止。

比如当有事件需要处理时,从链条的首个责任单元开始处理,首个责任单元处理事件中自己负责的部分,处理完之后,若事件还未处理完毕还需进一步处理,而同时当前责任单元无法处理或者不是自己负责的部分时,当前责任单元将事件传递给下一个责任单元,而后面该哪个责任单元处理,当前责任单元不关心,当前责任单元只需处理自己负责的部分并确定事件是否应该继续传递到下一责任单元。

 

责任链模式的优势:

①解耦,降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。

②易扩展,新增处理者只需往链上加节点即可,满足开闭原则。

③增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。

④责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的if或者if···else语句。

⑤责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

 

责任链模式的缺点:

①不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。

②对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。

③职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

 

责任链模式的UML类图:

52fe5e4959b14bb28eaf0875ea492a0c.png

责任链里一般包含4种角色:

①客户端Client:定义链的规则和运行方式,根据具体业务场景动态生成链(所以链并不是固定不变的,可定制组合,并选择链头和链尾);

②抽象处理者AbstractHandler:用于声明具体处理者的通用能力,一般包含抽象处理能力以及指向下一个节点的能力;

有一个nextHandler属性,用于指向下一个节点处理者;

有一个方法handleRequest(request):分析请求处理逻辑;

还有一个方法handle(request):定义每个具体处理者对象的具体处理方式;

③具体处理者ConcreteHandlers:实现抽象处理者接口,构成链中的处理节点,核心职能是处理请求,决定请求是在该节点消费掉还是沿着链继续传递(具体处理者之间独立且不可变)

可以看出,责任链模式核心的逻辑是处理和传递,同时具备由外部灵活定制的能力。

 

适用场景:

①有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定;

②在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;

③可动态指定一组对象处理请求;

其实只要涉及到逻辑顺序处理的,都可以使用责任链模式。但从实际场景出发,决定是否使用该模式要考虑一下两个因素:

①场景是不是够复杂,逻辑链是不是很长

②是否有灵活变化的业务变化场景需求

同时还要注意使用责任链不可避免带来的三个问题:

①处理者的数量问题。对链中请求处理者的遍历,如果处理者太多遍历必定会影响性能,特别是在一些递归调用中,所以要慎重

②代码出现问题时,不容易观察运行时的特征,有碍于排查问题

③需要cover请求即使传递到链尾端也一直没被处理,从而导致的一些异常问题

 

2.责任链模式举例

责任链模式常见的实现方式:

①声明AbstractHandler接口,通过创建抽象处理者消除具体处理者之间的重复模版代码;

②依次创建具体处理者子类及其实现方法,通过具体处理类决定当前处理类是否要消费这个请求还是沿着链继续传递;

③最终体现到业务层,由Client对象自行组装实现的链节点,实现逻辑处理和调用对象的解耦。

以费用报销为例,报销额度如果在领导的权限范围内就审批通过,否则就找再上一级领导去审批,以此类推。

先定义一个请求,也就是需要报销的额度:

public class MyRequest {

    private int money;

    public MyRequest(int money) {

        this.money = money;

    }

    get/set方法

}

抽象处理者AbstractHandler:

public abstract class AbstractHandler {

    protected AbstractHandler nextHandler;//下一节点的处理对象

    //定义处理者的处理逻辑(应该有哪个领导处理)

    public final void handleRequest( AbstractRequest request) {

        if (getLimit() >= request.getMoney()) {

            handle(request);//自己处理

        } else {

            if (nextHandler != null) {

                nextHandler.handleRequest( request); //转发给下一个处理者

            } else {

                System.out.println("当前所有处理者对象都不能处理该请求");

            }

        }

    }

    //用于判断自己能否处理

    protected abstract int getLimit();

    //每个处理者自己的具体处理方法

    protected abstract void handle( AbstractRequest request);

}

三个具体处理者:

public class Handler1 extends AbstractHandler {

    @Override

    protected int getLimit() {

        return 100; //项目经理处理100以内的报销

    }

    @Override

    protected void handle(MyRequest request) {

        Log.e("报销额度为" + request.getMoney() + ",项目经理Handler1 来处理");

    }

}

public class Handler2 extends AbstractHandler {

    @Override

    protected int getLimit() {

        return 200; //部门经理处理200以内的报销

    }

    @Override

    protected void handle(MyRequest request) {

        Log.e("报销额度为" + request.getMoney() + ",部门经理Handler2 来处理");

    }

}

public class Handler3 extends AbstractHandler {

    @Override

    protected int getLimit() {

        return 300; //总经理处理300以内的报销

    }

    @Override

    protected void handle(MyRequest request) {

        Log.e("报销额度为" + request.getMoney() + ",总经理Handler3 来处理");

    }

}

客户类Client:

AbstractHandler handler1 = new Handler1();

AbstractHandler handler2 = new Handler2();

AbstractHandler handler3 = new Handler3();

//处理者的下一个处理对象,构成责任链

handler1.nextHandler = handler2;

handler2.nextHandler = handler3;

//构造请求对象

MyRequest request = new MyRequest(105);

//从链式的首段开始发起请求

handler1.handleRequest(request1);

 

运行结果:报销额度为105,部门经理Handler2来处理

 

3.源码中用到的责任链模式

责任链的应用场景很多,比如:try - catch异常语句、Ordered Broadcast有序广播、ViewGroup/View的事件传递 、OKhttp网络请求、imageloader图片缓存加载等。

①Android事件分发机制是责任链模式最典型的应用:Activity、ViewGroup、View作为三个具体处理者,通过它们自身的dispatchTouchEvent()方法对事件进行消费或传递。

public boolean dispatchTouchEvent( MotionEvent ev) {

    if(onInterceptTouchEvent(ev)) {

            // onInterceptTouchEvent方法作为是否需要在本处理者中被消费的判断,如果为true则在本控件中消费

            this.onTouchEvent(ev);

    } else {

            //本控件不被拦截,则传递给下一个控件的dispatchTouchEvent方法

            next.dispatchTouchEvent(ev);

    }

}

这是一个非常经典的责任链模式,如果自己能处理就拦截下来自己干,如果自己不能处理或者不确定就交给责任链中下一个对象。 这种设计使得上层View既可以直接拦截该事件自己处理,也可以先询问(分发给)子View,如果子View需要就交给子View处理,如果子View不需要还能继续交给上层View处理。既保证了事件的有序性,又非常的灵活。

注意:当用户的点击事件传递到控件最顶端的View后,如果在该View中touch事件还没有被消费掉,那么它会依照原来传递过来的链路重新回到调用链最开始的地方,即从View的onTouch()或者onTouchEvent()重新回到Activity的onTouchEvent()方法中。这正是责任链模式需要特别注意的一点,如果请求到链的末端还没有被处理的话极有可能会让代码出现稳定性问题。所以Android通过重新将请求交回给最初的链节点方式来解决这个问题,这样做的好处是:

1)请求不论走到哪一步都可控(即一定会被处理,即使可能最终是空实现)

2)让和UI相关的功能类具备一致的行为方式(使 Activity、ViewGroup、View 均具备分发和消费能力)

②OkHttp框架中拦截器用到了责任链模式,通过责任链模式一层一层将请求进行封装并发起请求。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值