java设计模式之:责任链模式(企业级案例)

java设计模式一共有23种,其中主要分为三大类:

1:创建型模式

工厂方法模式、抽象工厂模式、单例模式、创建者模式、原型模式。

2:结构型模式

适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

3:行为模式

策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模状态模式、访问者模式、中介者模式、解释器模式。

今天我们主要讲解行为模式中的责任链模式:
 

白话讲责任链模式

什么是责任链模式:责任链模式,故名思意就是一个锁链一般,前一个扣着下一个,组成的一个链条。请求端只需要发起请求,但是不需要知道具体的实现。目的是为了解决请求端与实现端的解耦。

责任链一般由多个实现组成,当收到请求的时候处于责任链第一个实现会进行判断是否可以处理,不可以则传递给下一个处理,如此按照顺序执行。当然下一个是谁也是我们自己在定义的时候指定的,实现的执行顺序是我们在创建的时候指定的。

责任链的好处:

1.请求与实现解耦,实现之间管理维护方便。

2.具体实现不需要知道责任链的内部结构,只需要维护自己实现,降低了维护难度

3.可以修改内部链的执行顺序

4.新增实现简单方便。

责任链的弊端:

1.因为只关心自己内部实现,不关心链内部结构,开发调试会比较麻烦。因为你压根就不清楚他调用的会是哪一个实现。

2.增加系统的资源消耗。因为链式调用,可能会进行很多次判断,因为每个实现都会判断是否能够处理该请求,不能处理则调用下一个,增加了系统开销

3.不能保证请求被消化,正是因为其特殊的特性,在处理之前会判断是否能够处理,如果每一个链都不能处理,那么该请求无法被消化。

责任链的应用场景:java中的filter过滤器,各种权限控制。

图解:

java设计模式之:责任链模式(企业级案例)_第1张图片 责任链模式

 

通过上图我们简单分析一个责任链的原理,以及执行流程。为什么能解除调用者以及实现之间的耦合呢?

上诉流程图有两个角色非常重要,

第一个:我们的父类抽象方法,这里就暂且叫做abstractHandle把,我们的abstractHandle的作用就是提供抽象功能接口,以及提供设置下一个实现链的方法。

第二个:我们的实现工厂,暂且就叫做chainFactory,我们的chainFactory是用于管理我们的责任链的,他负责创建以及管理每个责任链的调用顺序,也就是执行顺序以及创建是在这里完成。

除了上诉的两个角色就是我们剩下的具体的实现了,每个实现只负责自己需要实现的部分,对于不满足要求的则调用下个实现。

上面简单的将我们责任链中的每个角色都简单的介绍了一下。那么接下来我们就按照一个简单的java例子并结合我们的上图进行讲解一下责任链模式。还可以参考我们java中的filter。

 

案例介绍:我们使用责任链设计一个简单的java公司请假批准程序,其中如果请假的天数在自己的可以受理范围内,则自己处理,如果不能处理则不出来,交给下一个实现,具体是那个处理,自己不用关心。

主要角色:

1.部门主管,受理请假时长为三天之内的请假请求。

2.人事经理,受理请假时长为四天到八天之内的请假请求。

3.项目经理,对大于八天的请假时长作处理,如果不大于12天,则允许,否则拒绝。

顺带一提。如果是传统处理方案的话,我们需要对请假时长作判断,用if elseif 或者switch进行条件判断调用不同的方法,但是使用责任链模式则可以避免多重if,以及switch。(只需要记住,责任链可以解决多重if以及switch)

那好下面我们开始代码编写:

1.首先我们先定义我们的abstractHandle类:

/**
 * 审核类
 *
 * @author 李昆城
 */
@Data
@SuppressWarnings("unused")
@AllArgsConstructor
@NoArgsConstructor
public abstract class BaseAudit {


    /**
     * 请假处理对象
     */
    protected BaseAudit audit;


    /**
     * 请假处理
     */
    abstract boolean vacateAudit(int number) throws Exception;

    /**
     * 开始下一个处理
     */
    boolean nextAudit(int number) throws Exception {
        return audit.vacateAudit(number);
    }

}

我们的abstractHandle只有两个方法以及一个成员属性,分别是用作处理请假,以及调用下一个实现处理请假和保存下一个实现的成员属性。

2.有了成员属性我们开始创建具体的实现:

部门主管


/**
 * 部门主管审核
 *
 * @author 李昆城
 */
public class DepartmentManagerAudit extends BaseAudit {


    @Override
    public boolean vacateAudit(int number) throws Exception {
        if (number > 3) {
            return nextAudit(number);
        }
        System.out.println("\t\n部门主管开始处理请假。");
        System.out.println("我是部门主管,我同意了");
        return true;
    }
}

人事经理


/**
 * 人事主管审核
 *
 * @author 李昆城
 **/
public class PersonnelManagerAudit extends BaseAudit {


    @Override
    public boolean vacateAudit(int number) throws Exception {
        if (number > 8) {
            return nextAudit(number);
        }
        System.out.println("\t\n人事主管开始处理请假。");
        System.out.println("我是人事主管,我同意了");
        return true;
    }
}

项目经理

/**
 * 项目经理
 *
 * @author 李昆城
 **/
public class ProjectManagerAudit extends BaseAudit {

    @Override
    public boolean vacateAudit(int number) throws Exception {
        System.out.println("\t\n项目经理开始处理请假。");
        if (number > 12) {
            throw new IllegalAccessException("项目紧张,请假天数不能大于3天,不予批准。");
        }
        System.out.println("我是项目经理,我同意了。");
        return true;
    }
}

3.有了我们具体的实现,那么我们需要一个工厂,为我们创建,并且管理我们的责任链。

/**
 * 审核工厂
 *
 * @author Administrator
 **/
public class AuditFactory {

    /**
     * 得到第一个审核人
     *
     * @return 审核
     */
    public DepartmentManagerAudit getBaseAudit() {
        //部门主管
        DepartmentManagerAudit departmentManagerAudit = new DepartmentManagerAudit();
        //人事经理
        PersonnelManagerAudit personnelManagerAudit = new PersonnelManagerAudit();
        departmentManagerAudit.setAudit(personnelManagerAudit);

        //项目经理
        ProjectManagerAudit projectManagerAudit = new ProjectManagerAudit();
        personnelManagerAudit.setAudit(projectManagerAudit);
        return departmentManagerAudit;
    }
}

我们的工厂可以很清晰的看到,我们创建了三个实现,分别是,部门主管、人事经理、项目经理,分别对应DepartmentManagerAudit,PersonnelManagerAudit,ProjectManagerAudit,并且指定了责任链执行的顺序,分别是,部门主管,人事经理,项目经理。

4.ok下面我们设计我们的请求调用者

/**
 * 启动类
 *
 * @author 李昆城
 */
public class App {


    public static void main(String[] args) {
        AuditFactory auditFactory = new AuditFactory();
        DepartmentManagerAudit baseAudit = auditFactory.getBaseAudit();
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 10; i++) {
            System.out.print("\t\n你好,请输入你的请假天数:");
            if (!scanner.hasNextInt()) {
                System.out.println("请输入合法的请假天数");
                continue;
            }
            int number = scanner.nextInt();
            System.out.println("请假申请已经提交。");
            try {
                if(baseAudit.vacateAudit(number)){
                    System.out.println("恭喜你,请假成功!");
                };

            } catch (Exception e) {
                System.out.println("请假失败:" + e.getMessage());
                continue;
            }
        }
    }
}

ok,可以看到我们通过工厂获取到我们的抽象审核请假的实例,然后输入请假请求,输入天数,调用我们的审核方法进行判断并且确定具体的处理人,但是在整个过程中调用者什么都不知道,也不知道具体实现,只知道自己提交了请假申请。这样就很好的解决了调用者和申请者之间的耦合,且每个角色(部门主管,人事主管,项目经理)等都只需要维护自己的实现方式,也便于维护,同样缺点就是如果发生问题,不好流程最终,相当于工厂是一个黑匣子,吧我们的具体实现完全给拒绝在外面

代码地址:https://gitee.com/happy_bug/designMode/tree/master/src/main/java/com/likuncheng/responsibilitychain

 

另外下面我会带来企业级的真实案例,这里只能贴出关键代码。

首先讲解一下需求:需求就是一个多角色多权限登录的一个功能,

就是多重角色的登录,登陆用户只需要告诉我你是什么角色,以及关键登录信息即可,调用方完全不知道具体每个角色的实现。

这里贴出部门关键代码:https://gitee.com/happy_bug/designMode/tree/master/src/main/java/com/likuncheng/responsibilitychain/enterprisecase

你可能感兴趣的:(java设计模式)