责任链模式
场景:
公司里面,报销个单据需要经过流程;
- 申请人填单申请,申请给经理;
- 小于1000,经理审核;超过1000,交给总经理审批
- 总经理审批通过;
结构
- 抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选)
- 具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。
- 客户类(Client):向一个链上的具体处理者ConcreteHandler对象提交请求。
结构图
案例:
公司请假的审批流程:
- 如果请假天数小于3天,主任审批;
- 如果请假天数大于3天,小于10天,经理审批
- 如果大于等于10天,小于30天,总经理审批;
- 如果大于等于30,提示拒绝
代码
/**
* 封装请假的基本信息
*/
public class LeaveRequest {
private String empName;//姓名
private int leaveDay;
private String reason;
public LeaveRequest(String empName, int leaveDay, String reason) {
this.empName = empName;
this.leaveDay = leaveDay;
this.reason = reason;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public int getLeaveDay() {
return leaveDay;
}
public void setLeaveDay(int leaveDay) {
this.leaveDay = leaveDay;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
/**
* 抽象类
*/
public abstract class Leader {
protected String name;
protected Leader nextLeader;
public Leader( String name) {
this.name = name;
}
//设置责任链上的后续对象
public void setNextLeader(Leader nextLeader){
this.nextLeader = nextLeader;
}
//处理请求核心的业务方法
public abstract void handleRequest(LeaveRequest request);
}
/**
* 主任类
*/
public class Director extends Leader{
public Director(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if(request.getLeaveDay()<3){
System.out.println("员工:"+request.getEmpName()+"请
假"+request.getLeaveDay()+"天");
System.out.println("主任:"+ this.name+" 审批通过");
}else {
if (this.nextLeader != null){
this.nextLeader.equals(request);
}
}
}
}
/**
* 经理
*/
public class Manager extends Leader{
public Manager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
int days = request.getLeaveDay();
if(days>=3 && days<10){
System.out.println("员工:"+request.getEmpName()+"请假"+days+"天");
System.out.println("经理:"+ this.name+" 审批通过");
//todo 处理
}else {
if (this.nextLeader != null){
this.nextLeader.equals(request);
}
}
}
}
/**
* 总经理
*/
public class GeneralManager extends Leader{
public GeneralManager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
int days = request.getLeaveDay();
if(days>=10 && days<30){
System.out.println("员工:"+request.getEmpName()+"请假"+days+"天");
System.out.println("经理:"+ this.name+" 审批通过");
//todo 处理
}else {
System.out.println("莫非想辞职,竟然想请假"+request.getLeaveDay()+"天");
}
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args){
Leader director = new Director("张三");
Leader manager = new Manager("李四");
Leader generalManager = new GeneralManager("王五");
//构建责任链模式
director.setNextLeader(manager);
manager.setNextLeader(generalManager);
LeaveRequest request = new LeaveRequest("Tom" , 1,"回家探亲");
director.handleRequest(request);
}
}
由于责任链的创建完全在客户端,因此新增的具体处理者对原有类库没有任何影响,只需添加新的类,然后在客户端调用时添加即可,符合开闭原则。
比如在案例中我们的审批流程添加一条规则: 大于等于10天小于30天,总经理审批
客户端责任链组织的两种方式
- 链表方式可以定义职责链
- 非链表方式实现职责链:通过集合、数组生成职责链更加实用!实际上,很多项目中,每个具体的Handler并不是由开发团队定义的,而是项目上线后由外部单位追加 的,所以使用链表方式定义COR链就很困难
使用中
- java中,异常机制就是一种责任链模式,一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch
- JavaScript语言中,事件的冒泡和捕获机制。java语言中,事件的处理采用观察者模式
- Servlet开发中,过滤器的链式处理
- Structs2中,拦截器的调用也是典型的责任链模式
职责链模式的优点:
- 降低耦合度 :该模式使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”地处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。
- 职责链可简化对象的相互连接 : 结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。
- 增强了给对象指派职责( R e s p o n s i b i l i t y )的灵活性 :当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。
- 增加新的请求处理类很方便
职责链模式的缺点:
- 不能保证请求一定被接收。既然一个请求没有明确的接收者,那么就不能保证它一定会被处理 —该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。