责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式。它的核心思想是将多个处理请求的对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。这种模式让请求的发送者不需要知道谁最终会处理它的请求,从而实现发送者和接收者的解耦,并允许多个对象都有机会处理请求
优点:
- 降低耦合度:请求发送者无需知道具体由哪个处理者处理请求,处理者也无需知道链的全貌。
- 增强灵活性与可扩展性:可以在运行时动态地添加、移除或修改链中的处理者顺序,符合"开闭原则"。
- 简化对象职责:每个具体处理者只需关注自己职责范围内的请求,符合"单一职责原则"。
缺点:
- 请求可能未被处理:如果链配置不当或没有合适的处理者,请求可能到达链的末端也无法被处理。
- 性能考虑:较长的责任链可能会带来性能开销,因为请求可能需要遍历多个对象。
- 调试难度:请求的传递是隐式的,调试时可能难以跟踪请求的处理路径和确定最终是哪个处理者处理的。
场景模拟:请假。 你是一个公司员工,在你的上方有许多领导,并且你的请假也是需要经过层层审批才能够通过。类图如下:
先关注两个地方: Handler(处理)接口:所有参与审批流程过的对象都必须要实现的就接口,接口中有两个方法。execute:执行是否通过你的请假申请的逻辑。setNextHander:设置自己审批之后的下一个对象是谁。
Handler的实现类:假设在我们的场景中,你的请假需要三个人的通过:1,你的mentor。2,你的leader。3,你们公司的总监Boss。那么这三个对象则都需要实现上述接口。
按照我们的期望来说,肯定是希望mentor审批之后,leader再审批,最后是Boss。如果我们直接硬编码实现会导致三者的执行过程混合在了一起,一旦某一个人的审批逻辑发生了变化就需要在公共的地方进行修改,那么这一部分的代码就会变得十分混乱。责任链的思想则是,让每一个参与流程的审批人能够刚感知到下一个审批人的存在,这样在该对象的内部就可以只考虑自己的审批过程,审批完之后调用下一个审批者的审批方法即可。这样一来每个审批者发生变化时,只需要改自己的代码,有新的审批者加入也很方便。
先来看一下我们的请假条实体类:
kotlin
@Data
public class LeaveRequestFormDTO {
//请假原因
private String Reason;
//请假天数
private Integer days;
}
Handler接口:
csharp
public interface Handler {
void execute(LeaveRequestFormDTO data);
void setNextHandler(Handler handler);
}
Mentor很好说话
kotlin
public class MentorHandler implements Handler{
private Handler nextHandler;
@Override
public void execute(LeaveRequestFormDTO data) {
System.out.println("Mentor觉得可以,通过你的申请");
if(this.nextHandler!=null){
this.nextHandler.execute(data);
}
}
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
}
Leader比较难搞
kotlin
public class LeaderHandler implements Handler{
private Handler nextHandler;
@Override
public void execute(LeaveRequestFormDTO data) {
if(data.getDays() > 20){
throw new RuntimeException("时间也太久了,不通过");
}
System.out.println("Leader觉得可以,通过你的申请");
if(this.nextHandler!=null){
this.nextHandler.execute(data);
}
}
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
}
老板简直是出生
kotlin
public class BossHandler implements Handler{
private Handler nextHandler;
@Override
public void execute(LeaveRequestFormDTO data) {
if(!data.getReason().contains("生病")){
throw new RuntimeException("没生病请什么假?");
}
System.out.println("Boss觉得可以,通过你的申请");
if(this.nextHandler!=null){
this.nextHandler.execute(data);
}
}
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
}
可以看到每个审批人都是有自己的逻辑的,但是毫无例外的都会在最后调用下一个审批人的审批方法。但是现在我们只是有了三个独立的类,如何将他们组装起来使审批行为变成链路呢?在我这里,BaseHandler并不是一个审批者,他只是用来将所有的审批对象进行组装,然后将第一个审批者回传给客户端的工具。当然也可以直接在客户端进行组装,我只是为了代码清爽,你可以有自己的风格。
csharp
public class BaseHandler {
//短暂的存储一下所有的审批者
private List<Handler> handlers= new ArrayList<>();
public List<Handler> getHandlers(){
return this.handlers;
}
//将暂存的所有审批者之间的关系进行链接,形成责任链
private void init(){
if(handlers.isEmpty()){
return;
}
for (int i=0; i<handlers.size(); i++){
Handler handler = handlers.get(i);
if(i+i <= handlers.size()){
handler.setNextHandler(handlers.get(i+1));
}
}
}
//简单工厂方法,创建所有的审批者
public static Handler build(){
BaseHandler baseHandler = new BaseHandler();
List<Handler> list = baseHandler.getHandlers();
MentorHandler mentorHandler = new MentorHandler();
LeaderHandler leaderHandler = new LeaderHandler();
BossHandler bossHandler = new BossHandler();
list.add(mentorHandler);
list.add(leaderHandler);
list.add(bossHandler);
baseHandler.init();
return baseHandler.getHandlers().get(0);
}
}
那么接下来在客户端你就可以开始请假啦:
csharp
public class Client {
public static void main(String[] args) {
LeaveRequestFormDTO dto = new LeaveRequestFormDTO();
dto.setDays(20);
dto.setReason("领导我生病了(实际还是请假的借口罢了)");
try{
Handler handler = BaseHandler.build();
handler.execute(dto);
System.out.println("恭喜你请假通过!!!");
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("很遗憾,你的请假审批流程被中断了。。。");
}
}
}
执行结果: Mentor觉得可以,通过你的申请 Leader觉得可以,通过你的申请 Boss觉得可以,通过你的申请 恭喜你请假通过!!!
Process finished with exit code 0