看了一些设计模式的书籍和文章,结合先前做过的一个真实的项目,对责任链模式作个小结
1.项目需求和背景
先前做过一个人力资源管理的产品,产品中有部分功能就是要实现员工请假审批流程,员工提交请假申请比较简单,无非就是填写一些请假单的基本信息,如请假的起至日期,请假类型(年假,病假),请假的天数,但是系统中的审批流程却比较纠结,审批的流程分为业务小组长审批->部门经理审批->副总裁审批->总裁审批->流程结束,就这样审批一层一层的传递下去,小组长只能审核1天以内的请假,部门经理能审批3天以下的请假,副总裁能审批5天以下的请假,总裁可以审批所有的请假条
2.BadPractice
早期的代码实现是 把这一坨的实现逻辑都放在一个公共的方法里的,一个万能的方法,所有的后期都搞到这里面,里面充斥着各种if else,典型的意大利面式的代码,后期每当听到老板说要改动请假的逻辑时,大家都怨声载道,不愿去碰这坨东西
3.用设计模式改善程序结构
看过设计模式的一些资料,感觉其中心思想在于隔离变化,封装抽象,把属于一个范畴的东西‘圈’起来,然后给每个特例一片自己的天地(通常是单独的类)去发展,这样作的好处在于,某个单独的规则改变的时候不会殃及池鱼。切到实际,我们来看责任链模式怎样解决这个流程问题的。<<设计模式>>一书中,作者给责任链模式一个很好的诠释的例子--击鼓传花,就是一个花(可理解为一个请求)在各个不同的角色(请求处理器)中传递,每个角色都可以对花(请求)作一些处理,然后传递给下一个,那么责任链的特色在哪里呢?首先他是一个‘链’,每个处理角色都知道要处理的下一级角色是谁,每个角色都拥有对该请求的处理权利
3.1我们的请假审批类图
概述:首先定义一个抽象的审核角色Approver,该角色持有一个下级审批人的对象--通过setNextApprover()来定义,然后有一个抽象的方法doApprove(LeaveRequest),表示当前角色对请假条的实际审核逻辑,GroupManager,DepartmentManager,VicePresident,President表示具体的审批角色,角色本身根据业务规则来定义当前的请假条是否属于自身的处理范畴内,审核后应该作那些操作--决定终结当前流程还是继续交给下一级审批者处理,LeaveRequestProcess是我们的main方法所在地,负责组装这些流程
3.2实现细节
LeaveRequestProcessor:
public static void main(String[] args){
LeaveRequest leaveRequest = new LeaveRequest();
leaveRequest.setApplyDays(2);
leaveRequest.setApplyId(1234);
leaveRequest.setApplyNick("张三");
leaveRequest.setLeaveType(1);//年假
//定义请假条流转流程骨架
//Group Manager->Department Manager->Vice President->President
GroupManager approver = new GroupManager();
DepartmentManager departmentManager = new DepartmentManager();
approver.setNextApprover(departmentManager);//这个是核心
VicePresident vicePresident = new VicePresident();
departmentManager.setNextApprover(vicePresident);
President president = new President();
vicePresident.setNextApprover(president);
president.setNextApprover(new NoneApprover());
approver.doApprove(leaveRequest);
}
VicePresident:
public void doApprove(LeaveRequest leaveRequest) {
logger.debug("------start-----");
if (leaveRequest.getApplyDays() <= 3 && leaveRequest.getApplyDays() > 2) {//这个是副总裁能处理的业务范畴
logger.debug("VicePresident-approved:" + leaveRequest);
//操作db,修改状态--这里只是个事例,省略实际存放db操作
}else{
nextApprover.doApprove(leaveRequest);
}
logger.debug("------end-----");
}