好用的设计模式 -- 责任链

责任链是一种日常开发常用的设计模式,这里之所以说它好用,是因为责任链的形式很贴合面向过程的开发思路,易于理解,同时链式也利于开发者归纳功能,管理代码。

其实这种设计模式很容易理解,我们都知道链表(单向)的数据结构:

class Node {
    
    private Node next;
    private Object value;

    ……(构造方法)
}

理解链表就很容易理解责任链:责任链是由多个执行对象构成的,它们都有两个共同的属性:一是“next”,表示下一个执行对象;二是执行方法,也就是说当前对象需要进行的操作方法。既然所有执行对象都有这两个共同的属性,我们就可以抽象出一个抽象类,它有一个基础属性“next”,和抽象方法:“handleWork”:

public abstract class Handler {
    
    protected Handler next;

    abstract protected String handleWork(Object obj);
}

看起来Node和Handler可以对应上,只是说Node没有具体的行为方法,而Handler有基础方法。
有以上的基础知识,咱们来实现这样一个场景:
咱们有一个收入证明需要申请公司盖章,这个过程中需要小组领导,部门主管,公司财务进行审批。只有顺次通过之后,才可以最终获得公章。这里我们可以按照责任链的思路进行实现:

1. 创建证明的抽象类 Certification.java,虽然是个示例,但是我们还是按照真实设计出发,证明的类型可能有很多,比如收入证明,结婚证明,核算证明等等,咱们抽象出一个证明类,然后创建它的子类IncomeCertification.java。

public abstract class Certification {

    protected String name;

    /**
     * 1 - 收入证明
     * 2 - 核算证明
     * 3 - 结婚证明
     */
    private Integer type;

    private String owner;

    //... get and set methods
}
public class IncomeCertification extends Certification {

    private Integer income;

   //... get and set methods
}

ok!entity定义完成,可以看到,收入证明有4个属性,其中名称、类型、拥有者是继承自父类,具体收入是个性化属性。现在咱们定义责任链执行对象的基类:

public abstract class Handler {

    protected Handler next;

    abstract protected boolean processCertification(Certification cert);
}

对于小组领导来说,他需要确认该申请人属于自己团队:

public class GroupLeaderHandler extends Handler {

    private static List<String> teamMember = new ArrayList<String>();

    static {
        teamMember.add("ruiruiyuzhi");
        teamMember.add("zhangsan");
    }

    @Override
    protected boolean processCertification(Certification cert) {
        if (teamMember.contains(cert.getOwner())) {
            return this.next.processCertification(cert);
        }
        return false;
    }
}

对于部门领导来说,他需要确认收入无误:

public class DepartmentLeaderHandler extends Handler {

    private static final Integer INCOME_TYPE = 1;
    private static final Integer INCOME = 1000;

    @Override
    protected boolean processCertification(Certification cert) {
        IncomeCertification incomeCert = (IncomeCertification) cert;
        if (INCOME_TYPE.equals(cert.getType()) && INCOME.equals(incomeCert.getIncome())) {
            return this.next.processCertification(cert);
        }
        return false;
    }
}

财务人员判断申请类型为已有类型,则审批通过:

public class FinancialHandler extends Handler {

    private static List<Integer> certType = new ArrayList<Integer>();

    static {
        certType.add(1);
        certType.add(2);
        certType.add(3);
    }
    
    @Override
    protected boolean processCertification(Certification cert) {
        return certType.contains(cert.getType()); 
    }
}

到目前为止我们准备好了各个责任链环节的执行对象,进而需要将其串成链,这个过程跟链表的初始化相似:

    public static void main(String[] args) {
        //1.初始化责任链
        GroupLeaderHandler groupLeaderHandler = new GroupLeaderHandler();
        DepartmentLeaderHandler departmentLeaderHandler = new DepartmentLeaderHandler();
        FinancialHandler financialHandler = new FinancialHandler();
        groupLeaderHandler.setNext(departmentLeaderHandler);
        departmentLeaderHandler.setNext(financialHandler);
                                             ……

其次,构建待审批的证明对象:

    public static void main(String[] args) {
        //1.初始化责任链
        GroupLeaderHandler groupLeaderHandler = new GroupLeaderHandler();
        DepartmentLeaderHandler departmentLeaderHandler = new DepartmentLeaderHandler();
        FinancialHandler financialHandler = new FinancialHandler();
        groupLeaderHandler.setNext(departmentLeaderHandler);
        departmentLeaderHandler.setNext(financialHandler);
        //2.构建证明对象
        IncomeCertification myIncomeCert = new IncomeCertification();
        myIncomeCert.setIncome(1000);
        myIncomeCert.setName("income certification");
        myIncomeCert.setOwner("ruiruiyuzhi");
        myIncomeCert.setType(1);

这时候我们就需要进入责任链开始审核了,但是入口在哪呢?当然,你可以强行把GroupLeaderHandler中加入一个public方法,作为入口,但是这样做扩展性不好,比方说这条审核的链条有新环节加入,或者有环节精简,改变了入口,岂不是需要重新编写入口?
其实我们可以把入口放在Handler中,这个方法意味着从当前环节开始,往下走,这样我们只需要根据业务需要改变入口对象即可:

public abstract class Handler {

    protected Handler next;

    abstract protected boolean processCertification(Certification cert);

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }
    //从当前结点开始,往下走
    public boolean processFromCurrentHandler(Certification cert) {
        return this.processCertification(cert);
    }
}

这样,我们在Main方法中去测试整个流程可以发现,责任链的形式跑通了。

public class MainApplication {

    public static void main(String[] args) {
        GroupLeaderHandler groupLeaderHandler = new GroupLeaderHandler();
        DepartmentLeaderHandler departmentLeaderHandler = new DepartmentLeaderHandler();
        FinancialHandler financialHandler = new FinancialHandler();
        groupLeaderHandler.setNext(departmentLeaderHandler);
        departmentLeaderHandler.setNext(financialHandler);

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

推荐阅读更多精彩内容