Android源码设计模式学习笔记-责任链模式

当处理一个事件是根据这个事件的某个条件去决定哪个处理对象的时候可以考虑使用责任链模式.


image.png

具体我们从一个代码示范入手,定义一个抽象的处理者

public abstract class AbstractHandler {
    public AbstractHandler nextHandler;

    /**
     * 处理请求,当Request Level 和 Handle Level相等就表明该请求交由该处理者处理
     */
    public final void handleRequest(AbstractRequest request){
        if (getHandleLevel() == request.getRequestLevel()){
            handle(request);
        }else {
            if (nextHandler != null){
                nextHandler.handle(request);
            } else{
                System.out.println("All of handler can not handle the request");
            }
        }
    }

    /**
     * 获取处理对象的处理级别
     * @return
     */
    protected abstract int getHandleLevel();

    /**
     * 每个处理对象的具体处理方式
     */
    protected abstract void handle(AbstractRequest request);

}

再定义一个抽象的请求

public abstract class AbstractRequest {
    private Object obj;

    public AbstractRequest(Object obj) {
        this.obj = obj;
    }

    /**
     * 获取处理内容的对象
     */
    public Object getContent(){
        return obj;
    }

    /**
     * 获取请求级别
     */
    public abstract int getRequestLevel();
}

下面分别定义3个实际的处理者和3个实际的请求

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());
    }
}
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;
    }
}

最终调用

Handler1 handler1 = new Handler1();
Handler2 handler2 = new Handler2();
Handler3 handler3 = new Handler3();
/**
* 构建责任链
*/
handler1.nextHandler = handler2;
handler2.nextHandler = handler3;

Request1 request1 = new Request1("request 1");
Request2 request2 = new Request2("request 2");
Request3 request3 = new Request3("request 3");

handler1.handleRequest(request1);
handler1.handleRequest(request2);
handler3.handleRequest(request3);

输出:

01-13 21:33:44.684 22261-22261/? I/System.out: Handler1 handle request : 1
01-13 21:33:44.684 22261-22261/? I/System.out: Handler2 handle request : 2
01-13 21:33:44.684 22261-22261/? I/System.out: Handler3 handle request : 3

上面我们创建Request并交给Handler构建的一条责任链处理,当满足Request的Level和Handler的Level相等的情况就交由该Handler进行处理,这就是一个责任链的基本实现.
下面在再举一个实际栗子看看运用上面这套责任链模式代码.
目前小明出国出差回来,出差的经费是50000元,小明需要报销这笔经费,他首先找到他的组长处理报销问题,但是组长这边只能处理1000元以下的报销,组长表示找上面的部门主管批复,于是找到部门主管,部门主管只能处理5000以下的报销,于是部门主管找到经理批复,经理只能处理10000元以下的报销,于是经理找到老板,进行报销批复。处理报销经费事件这一连串人可以看作是一个责任链,我们可以用责任链模式去实现上面的需求.
先抽象领导

public abstract class Leader {
    //上级领导
    public Leader nextHandler;

    public final void handleRequest(int money){
        /**
         * 如果报销经费小于该领导的处理范围,则处理.
         */
        if (money < limit()){
            handle(money);
        } else {
            /**
             * 不满足交给上级领导进行处理
             */
            if (null != nextHandler){
                nextHandler.handleRequest(money);
            }
        }
    }

    /**
     * 处理经费上限
     * @return
     */
    public abstract int limit();

    /**
     * 处理报销
     * @param money
     */
    protected abstract void handle(int money);
}

具体的四个领导

public class GroupLeader extends Leader{
    @Override
    public int limit() {
        return 1000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("组长批复报销 "+money+" 元");
    }
}
public class Director extends Leader{
    @Override
    public int limit() {
        return 5000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("主管批复报销 "+money+"元");
    }
}
public class Manager extends Leader{
    @Override
    public int limit() {
        return 10000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("经理批复报销 "+money+"元");
    }
}
public class Boss extends Leader{
    @Override
    public int limit() {
        return Integer.MAX_VALUE;
    }

    @Override
    protected void handle(int money) {
        System.out.println("老板批复报销"+money+"元");
    }
}

最后调用

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);

输出

01-13 21:48:40.181 22459-22459/? I/System.out: 老板批复报销50000元

其实责任链模式也并不是一定要按照上面那套模版代码去实现,关键是要突出处理一个事件的处理者再不满足处理该事件条件的情况下把事件传递给下一个处理者这种思想. 最后再来一个栗子,在Android开发中广播分为两种,一种是Normal Broadcast另外一种是Order Broadcast, 发送Normal Broadcast是所有注册该广播的广播接收者都能接收到。Order Broadcast是按照广播接收者优先级依次发送,接收到该广播的广播接收者可以选择是否继续向下传递,我们可以利用Order Broadcast这样的机制来实现一条责任链.

public class FirstBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        int limit = intent.getIntExtra("limit",-1001);
        if (limit == 1000){
            String msg = intent.getStringExtra("msg");
            Toast.makeText(context,msg,Toast.LENGTH_SHORT).show();
            abortBroadcast();
        } else {
            Bundle b = new Bundle();
            b.putString("new","Message from FirstReceiver");
            setResultExtras(b);
        }
    }
}
public class SecondBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        int limit = intent.getIntExtra("limit",-1001);
        if (limit == 100){
            String msg = intent.getStringExtra("msg");
            //取上一个receiver的附加信息
            Bundle b = getResultExtras(true);
            String str = b.getString("new");

            Toast.makeText(context,msg+" ----- "+str,Toast.LENGTH_SHORT).show();

            abortBroadcast();
        }else{
            Bundle b = new Bundle();
            b.putString("new","Message from SecondReceiver");
            setResultExtras(b);
        }
    }
}
public class ThirdBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        int limit = intent.getIntExtra("limit",-1001);

        if (limit == 10){
            String msg = intent.getStringExtra("msg");

            Bundle b = getResultExtras(true);
            String str = b.getString("new");

            Toast.makeText(context,msg+" ---- "+str,Toast.LENGTH_SHORT).show();

            abortBroadcast();
        }else{
            Bundle b = new Bundle();
            b.putString("new","Message from ThirdReceiver");
            setResultExtras(b);
        }
    }
}

在AndroidManifest.xml中申明这3个Receiver,并设置对应的权限值.

        <receiver android:name=".broadcast.FirstBroadcastReceiver">
            <intent-filter
                android:priority="1000"
                >
                <action android:name="com.example.huangli.action.ORDER_BROADCAST"></action>
            </intent-filter>
        </receiver>
        <receiver android:name=".broadcast.SecondBroadcastReceiver">
            <intent-filter
                android:priority="100"
                >
                <action android:name="com.example.huangli.action.ORDER_BROADCAST"></action>
            </intent-filter>
        </receiver>
        <receiver android:name=".broadcast.ThirdBroadcastReceiver">
            <intent-filter
                android:priority="10"
                >
                <action android:name="com.example.huangli.action.ORDER_BROADCAST"></action>
            </intent-filter>
        </receiver>

最后调用:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendBroadcast();
    }

    private void sendBroadcast() {
        Intent intent = new Intent();
        intent.setAction("com.example.huangli.action.ORDER_BROADCAST");
        intent.putExtra("limit", 100);
        intent.putExtra("msg", "Message from MainActivity");
        sendOrderedBroadcast(intent, null);
    }

}

我们将limit设置成了100,它会在SecondBroadcastReceiver进行处理,实际效果大家可以试试。

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

推荐阅读更多精彩内容