java设计模式一共有23种,其中主要分为三大类:
1:创建型模式
工厂方法模式、抽象工厂模式、单例模式、创建者模式、原型模式。
2:结构型模式
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
3:行为模式
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模状态模式、访问者模式、中介者模式、解释器模式。
今天我们主要讲解行为模式中的责任链模式:
白话讲责任链模式
什么是责任链模式:责任链模式,故名思意就是一个锁链一般,前一个扣着下一个,组成的一个链条。请求端只需要发起请求,但是不需要知道具体的实现。目的是为了解决请求端与实现端的解耦。
责任链一般由多个实现组成,当收到请求的时候处于责任链第一个实现会进行判断是否可以处理,不可以则传递给下一个处理,如此按照顺序执行。当然下一个是谁也是我们自己在定义的时候指定的,实现的执行顺序是我们在创建的时候指定的。
责任链的好处:
1.请求与实现解耦,实现之间管理维护方便。
2.具体实现不需要知道责任链的内部结构,只需要维护自己实现,降低了维护难度
3.可以修改内部链的执行顺序
4.新增实现简单方便。
责任链的弊端:
1.因为只关心自己内部实现,不关心链内部结构,开发调试会比较麻烦。因为你压根就不清楚他调用的会是哪一个实现。
2.增加系统的资源消耗。因为链式调用,可能会进行很多次判断,因为每个实现都会判断是否能够处理该请求,不能处理则调用下一个,增加了系统开销
3.不能保证请求被消化,正是因为其特殊的特性,在处理之前会判断是否能够处理,如果每一个链都不能处理,那么该请求无法被消化。
责任链的应用场景:java中的filter过滤器,各种权限控制。
图解:
通过上图我们简单分析一个责任链的原理,以及执行流程。为什么能解除调用者以及实现之间的耦合呢?
上诉流程图有两个角色非常重要,
第一个:我们的父类抽象方法,这里就暂且叫做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