Android 责任链模式

源码地址

介绍

它是一种行为型设计模式之一。它的每一个节点都可以看作是一个对象,每一个对象拥有不同的处理逻辑,将一个请求从链式的首端发出,沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止,这就是责任链模式。

使用场景

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

示例一

说明:此为简化版代码,分为抽象处理者,具体的处理者。代码如下:

  1. 抽象处理者

    public abstract class Handler {
        protected Handler successor;    //下一节点的处理者
    
        /**
         * 请求处理
         * @param condition 请求条件
         */
        public abstract void handleRequest(String condition);
    }
    
  2. 具体的处理者1

    public class ConcreteHandler1 extends Handler {
        @Override
        public void handleRequest(String condition) {
            if (condition.equals("ConcreteHandler1")) {
                System.out.println("ConcreteHandler1 handled");
            } else {
                successor.handleRequest(condition);
            }
        }
    }
    
  3. 具体的处理者2

    public class ConcreteHandler2 extends Handler {
        @Override
        public void handleRequest(String condition) {
            if (condition.equals("ConcreteHandler2")) {
                System.out.println("ConcreteHandler2 handled");
            } else {
                successor.handleRequest(condition);
            }
        }
    }
    
  4. 客户类

    public class Client {
        public static void main(String[] args) {
            //构造一个ConcreteHandler1对象
            ConcreteHandler1 handler1 = new ConcreteHandler1();
            //构造一个ConcreteHandler2对象
            ConcreteHandler2 handler2 = new ConcreteHandler2();
            //设置handler1的下一个节点
            handler1.successor = handler2;
            //设置handler2的下一个节点
            handler2.successor = handler1;
            //处理请求
            handler1.handleRequest("ConcreteHandler2");
        }
    }
    

示例二

说明:抽象处理者,抽象请求者,请求者,处理者。代码如下:

  1. 抽象处理者

    public abstract class AbstractHandler {
        protected AbstractHandler nextHandler;    //下一节点的处理者对象
    
        /**
         * 请求处理
         * @param request 请求条件
         */
        public final void handleRequest(AbstractRequest request) {
            //判断当前处理者对象的处理级别是否与请求者的处理级别一致
            if (getHandleLevel() == request.getRequestLevel()) {
                //一致则由该处理对象处理
                handle(request);
            } else {
                //否则将该请求对象转发给下一个节点上的请求对象
                if (nextHandler != null) {
                    nextHandler.handleRequest(request);
                } else {
                    //所有处理者对象均不能处理该请求时输出
                    System.out.println("All of handler can not handle the request");
                }
            }
        }
    
        /**
         * 获取处理者对象的处理级别
         * @return  处理级别
         */
        protected abstract int getHandleLevel();
    
        /**
         * 每个处理者对象的具体处理方式
         * @param request   请求者对象
         */
        protected abstract void handle(AbstractRequest request);
    }
    
  2. 抽象请求者

    public abstract class AbstractRequest {
        private Object obj; //处理对象
    
        public AbstractRequest(Object obj) {
            this.obj = obj;
        }
    
        public Object getContent() {
            return obj;
        }
    
        /**
         * 获取请求级别
         * @return  请求级别
         */
        public abstract int getRequestLevel();
    }
    
  3. 请求者

    public class Request1 extends AbstractRequest {
        public Request1(Object obj) {
            super(obj);
        }
    
        @Override
        public int getRequestLevel() {
            return 1;
        }
    }
    
    public class Request2 extends AbstractRequest {
        public Request2(Object obj) {
            super(obj);
        }
    
        @Override
        public int getRequestLevel() {
            return 2;
        }
    }
    
    public class Request3 extends AbstractRequest {
        public Request3(Object obj) {
            super(obj);
        }
    
        @Override
        public int getRequestLevel() {
            return 3;
        }
    }
    
  4. 处理者

    public class Handler1 extends AbstractHandler {
        @Override
        protected int getHandleLevel() {
            return 1;
        }
    
        @Override
        protected void handle(AbstractRequest request) {
            System.out.println("Handler1 handle request:" + request.getRequestLevel());
        }
    }
    
    public class Handler2 extends AbstractHandler {
        @Override
        protected int getHandleLevel() {
            return 2;
        }
    
        @Override
        protected void handle(AbstractRequest request) {
            System.out.println("Handler2 handle request:" + request.getRequestLevel());
        }
    }
    
    public class Handler3 extends AbstractHandler {
        @Override
        protected int getHandleLevel() {
            return 3;
        }
    
        @Override
        protected void handle(AbstractRequest request) {
            System.out.println("Handler3 handle request:" + request.getRequestLevel());
        }
    }
    
  5. 客户类

    public class Client {
        public static void main(String[] args) {
            //构造3个处理者对象
            AbstractHandler handler1 = new Handler1();
            AbstractHandler handler2 = new Handler2();
            AbstractHandler handler3 = new Handler3();
    
            //设置当前处理者对象下一个节点的处理者对象
            handler1.nextHandler = handler2;
            handler2.nextHandler = handler3;
    
            //构造3个请求者对象
            AbstractRequest request1 = new Request1("Request1");
            AbstractRequest request2 = new Request2("Request2");
            AbstractRequest request3 = new Request3("Request3");
    
            //总是从链式的首端发起请求
            handler1.handleRequest(request1);
            handler1.handleRequest(request2);
            handler1.handleRequest(request3);
        }
    }
    

示例三

说明:小明出差学些新技术,其中花费了5w元,于是小明去找组长报销费用。。。代码如下:

  1. 抽象领导者

    public abstract class Leader {
        //上一级领导处理者
        protected Leader nextHandler;
    
        /**
         * 处理报账请求
         * @param money 能批复的报账额度
         */
        public final void handleRequest(int money) {
            if (money <= limit()) {
                handle(money);
            } else {
                if (nextHandler != null) {
                    nextHandler.handleRequest(money);
                }
            }
        }
    
        /**
         * 自身能够批复的额度权限
         * @return  额度
         */
        protected abstract int limit();
    
        /**
         * 处理报账行为
         * @param money 具体金额
         */
        protected abstract void handle(int money);
    }
    
  2. 具体的领导者

    public class GroupLeader extends Leader {
    
        @Override
        protected int limit() {
            return 1000;
        }
    
        @Override
        protected void handle(int money) {
            System.out.println("组长批复报销" + money + "元");
        }
    }
    
    public class Director extends Leader {
    
        @Override
        protected int limit() {
            return 5000;
        }
    
        @Override
        protected void handle(int money) {
            System.out.println("主管批复报销" + money + "元");
        }
    }
    
    public class Manager extends Leader {
    
        @Override
        protected int limit() {
            return 10000;
        }
    
        @Override
        protected void handle(int money) {
            System.out.println("经理批复报销" + money + "元");
        }
    }
    
    public class Boss extends Leader {
    
        @Override
        protected int limit() {
            return Integer.MAX_VALUE;
        }
    
        @Override
        protected void handle(int money) {
            System.out.println("老板批复报销" + money + "元");
        }
    }
    
  3. 客户类小明

    public class XiaoMing {
        public static void main(String[] args) {
            //构造各个领导对象
            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(50000);
        }
    }
    

    小明先找组长报账,然后组长找到主管,主管找到经理,经理最后找到老板解决。

    当然也可以直接跳过某个人。

对于责任链中的一个处理者对象,其只有两种行为,一是处理请求,二是将请求转送给下一个节点,不允许某个处理者对象在处理了请求后又将请求转送给上一个节点的情况。

对于一条责任链来说,一个请求最终只有两种情况,一个呗某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称该责任链为纯的责任链,对于后一种情况我们称为不纯的责任链,在实际应用中,我们所见到的责任链模式大多为不纯的责任链。

Android 源码中的实现

事件的分发处理。

责任链模式实战

说明:有序广播的处理。源码地址

  1. 广播接收者

    public class FirstReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取Intent中附加的限制值
            int limit = intent.getIntExtra("limit", -1001);
            //如果限制值等于1000,则处理,否则继续转发给下一个Receiver
            if (limit == 1000) {
                //获取Intent中附加的字符串消息并Toast
                String msg = intent.getStringExtra("msg");
                Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
    
                //终止广播
                abortBroadcast();
            } else {
                //添加信息发送给下一个Receiver
                Bundle bundle = new Bundle();
                bundle.putString("new", "Message from FirstReceiver");
                setResultExtras(bundle);
            }
        }
    }
    
    public class SecondReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取Intent中附加的限制值
            int limit = intent.getIntExtra("limit", -1001);
            //如果限制值等于100,则处理,否则继续转发给下一个Receiver
            if (limit == 100) {
                //获取Intent中附加的字符串消息并Toast
                String msg = intent.getStringExtra("msg");
    
                //获取上一个Receiver增加的消息
                Bundle bundle = getResultExtras(true);
                String str = bundle.getString("new");
                Toast.makeText(context, msg + "-----" + str, Toast.LENGTH_SHORT).show();
    
                //终止广播
                abortBroadcast();
            } else {
                //添加信息发送给下一个Receiver
                Bundle bundle = new Bundle();
                bundle.putString("new", "Message from SecondReceiver");
                setResultExtras(bundle);
            }
        }
    }
    
    public class ThirdReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取Intent中附加的限制值
            int limit = intent.getIntExtra("limit", -1001);
            //如果限制值等于10,则处理,否则继续转发给下一个Receiver
            if (limit == 10) {
                //获取Intent中附加的字符串消息并Toast
                String msg = intent.getStringExtra("msg");
    
                //获取上一个Receiver增加的消息
                Bundle bundle = getResultExtras(true);
                String str = bundle.getString("new");
                Toast.makeText(context, msg + "-----" + str, Toast.LENGTH_SHORT).show();
    
                //终止广播
                abortBroadcast();
            } else {
                //添加信息发送给下一个Receiver
                Bundle bundle = new Bundle();
                bundle.putString("new", "Message from ThirdReceiver");
                setResultExtras(bundle);
            }
        }
    }
    
  2. 部分清单文件数据

    <receiver android:name="com.yan.iterator.FirstReceiver">
        <intent-filter android:priority="1000">
            <action android:name="com.yan.iterator.action.ORDER_BROADCAST"/>
        </intent-filter>
    </receiver>
    <receiver android:name="com.yan.iterator.SecondReceiver">
        <intent-filter android:priority="100">
            <action android:name="com.yan.iterator.action.ORDER_BROADCAST"/>
        </intent-filter>
    </receiver>
    <receiver android:name="com.yan.iterator.ThirdReceiver">
        <intent-filter android:priority="10">
            <action android:name="com.yan.iterator.action.ORDER_BROADCAST"/>
        </intent-filter>
    </receiver>
    
  3. MainActivity

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent();
                    intent.setAction("com.yan.iterator.action.ORDER_BROADCAST");
                    intent.putExtra("limit", 100);
                    intent.putExtra("msg", "Message from MainActivity");
                    sendOrderedBroadcast(intent, null);
                }
            });
        }
    }
    

总结

  • 优点

    可以对请求者和处理者关系解耦,提高代码的灵活性。

  • 缺点

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

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

推荐阅读更多精彩内容