行为型模式之责任链模式

在设计模式中,责任链模式是属于行为模式,请求从一个起点开始,沿着任务链依次传递给下一个节点,直到某个节点处理了该请求而结束。

责任链中的每个节点都有机会去处理该请求,且发送方不需要关心接收方(链)的结构,这样就有效的避免了发送者和接收者之间的耦合。

在Android中,Touch事件分发流程就是典型的责任链模式,事件沿着Activity、ViewGroup和View传递,直到其中某一方消费了该事件为止。


image.png
举个栗子

公司员工级别:普通员工、部门经理、总经理、老板
普通员工需要请假,2天需要部门经理批准,5天需要总经理批准,10天需要老板批准。

首先,编写员工类

public class Staff {

    // 员工需要请假天数所在level
    // 1:10天以内,此时需Boss批准
    // 2:5天以内,此时需GeneralManager批准
    // 3:2天以内,此时需OrdinaryManager批准
    // 其他:谁也不会批准
    private int level;

    // 请假描述
    private String request;

    public Staff(int level) {
        this.level = level;
        switch (this.level) {
            case 1:
                this.request = "员工请假10天以内";
                break;
            case 2:
                this.request = "员工请假5天以内";
                break;
            case 3:
                this.request = "员工请假2天以内";
                break;
            default:
                this.request = "员工请假超过10天";
                break;
        }
    }

    // 获取员工需要请假天数所在level
    public int getLevel() {
        return level;
    }

    // 请假描述
    public String getRequest() {
        return request;
    }
}

编写Manger类,此类是一个抽象类

public abstract class Manager {

    // 员工等级
    public static final int BOSS = 1;// 老板
    public static final int GENERAL_MANAGER = 2;// 总经理
    public static final int ORDINARY_MANAGER = 3;// 部门经理

    private int level;

    private Manager nextManger;

    public Manager(int level) {
        this.level = level;
    }

    // 设置下一个处理节点
    public void setNextManger(Manager nextManger) {
        this.nextManger = nextManger;
    }

    public final void request(Staff staff) {
        // 获取请假等级和当前manager等级进行比较,如果相等,则当前manager有权限批准
        if (staff.getLevel() == level) {
            // 调用子类manager的处理
            response(staff);
        } else {
            // 如果nextManger不为null,即存在下一个处理节点
            if (nextManger != null) {
                // 下一个处理节点来处理该请求,这里使用了递归调用
                nextManger.request(staff);
            } else {
                // 没有下一个处理者
                System.out.println("项目紧张,无法批准这么多天假期");
                System.out.println("==========================");
            }
        }
    }

    // 抽象方法,需要子类实现
    protected abstract void response(Staff staff);
}

下面是实现三个Manger的子类

// 老板
public class Boss extends Manager {

    public Boss() {
        super(Manager.BOSS);
    }

    // 处理请求
    @Override
    protected void response(Staff staff) {
        System.out.println("员工问Boss");
        System.out.println(staff.getRequest());
        System.out.println("Boss回答OK");
        System.out.println("==========================");
    }
}
// 总经理
public class GeneralManager extends Manager {

    public GeneralManager() {
        super(Manager.GENERAL_MANAGER);
    }

    // 处理请求
    @Override
    protected void response(Staff staff) {
        System.out.println("员工问GeneralManager");
        System.out.println(staff.getRequest());
        System.out.println("GeneralManager回答OK");
        System.out.println("==========================");
    }
}
// 部门经理
public class OrdinaryManager extends Manager {

    public OrdinaryManager() {
        super(Manager.ORDINARY_MANAGER);
    }

    // 处理请求
    @Override
    protected void response(Staff staff) {
        System.out.println("员工问OrdinaryManager");
        System.out.println(staff.getRequest());
        System.out.println("OrdinaryManager回答OK");
        System.out.println("==========================");
    }
}

最后是发起员工的请假事宜

public class TestMain {

    public static void main(String[] args) {

        // 1...4之间随机数,作为员工请假等级,对应manager的等级
        Random random = new Random();
        ArrayList<Staff> arrayList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            arrayList.add(new Staff(random.nextInt(4)));
        }

        // 三个manager对象
        Manager ordinaryManager = new OrdinaryManager();
        Manager generalManager = new GeneralManager();
        Manager boss = new Boss();

        // 设置责任链的下一个处理节点
        // 部门经理之后是总经理
        ordinaryManager.setNextManger(generalManager);
        // 总经理之后是老板
        generalManager.setNextManger(boss);

        // 为了体现不同请假等级后的不同处理情况,这里用一个数组来产生多个请求
        for (Staff staff : arrayList) {
            // 开始第一个节点的请求
            ordinaryManager.request(staff);
        }
    }
}

执行结果(随机)

员工问OrdinaryManager
员工请假2天以内
OrdinaryManager回答OK
==========================
员工问OrdinaryManager
员工请假2天以内
OrdinaryManager回答OK
==========================
员工问OrdinaryManager
员工请假2天以内
OrdinaryManager回答OK
==========================
员工问GeneralManager
员工请假5天以内
GeneralManager回答OK
==========================
员工问OrdinaryManager
员工请假2天以内
OrdinaryManager回答OK
==========================
员工问OrdinaryManager
员工请假2天以内
OrdinaryManager回答OK
==========================
员工问OrdinaryManager
员工请假2天以内
OrdinaryManager回答OK
==========================
项目紧张,无法批准这么多天假期
==========================
员工问GeneralManager
员工请假5天以内
GeneralManager回答OK
==========================
项目紧张,无法批准这么多天假期
==========================

Process finished with exit code 0
image.png
角色分析
  • Manager:抽象处理者角色,声明一个处理请求的方法,并保持对下一个处理节点Manager对象的引用
  • Boss:具体的处理者,对请求进行处理,如果不处理就讲请求转发给下一个节点上的处理对象(GeneralManager、OrdinaryManager同Boss)
优点
  • 降低耦合度,将请求的发送者和接收者解耦,便于拓展,提高代码灵活性。
  • 简化了对象。使得对象不需要知道链的结构。
  • 增强给对象指派责任节点的灵活性,通过改变链内的成员或者调动它们的次 序,允许动态地新增或者删除责任节点。
缺点
  • 如果责任链太长,或者每条链判断处理的时间太长会影响性能。特别是递归循环的时候。
  • 请求不一定能得到处理,可能会没有对象处理。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354