1.概述

职责链模式是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止

职责链模式主要包含以下角色:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

1.1代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.zhen.studytotal.design.chain;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

/**
* Description: 设计模式-责任链模式
* User: zhen0w0
* Date: 2025/3/9
* Time: 19:07
*/
public class ChainTest {

public static void main(String[] args) {
User user = new User("zhen","123456","admin");

LoginService loginService = new LoginService();
loginService.login(user);

System.out.println("-----------------");
user.setPassword("123");
loginService.login(user);
System.out.println("-----------------");
user.setPassword("123456");
user.setRole("abcd");
loginService.login(user);

}
}


@Data
@AllArgsConstructor
class User{
private String username;
private String password;
private String role;
}

//handle抽象类
abstract class Handle{
protected Handle next;
public void next(Handle next){
this.next = next;
}
public abstract void doHandle(User user);
}

//用户名密码空校验
class ValidateHandler extends Handle{
@Override
public void doHandle(User user) {
if (StringUtils.isBlank(user.getPassword()) || StringUtils.isBlank(user.getUsername())){
System.out.println("用户名或密码为空!");
}
System.out.println("用户名密码校验通过");
next.doHandle(user);
}
}


// 登录校验,校验用户名是否匹配密码
class LoginHandler extends Handle {
@Override
public void doHandle(User user) {
if (!"zhen".equals(user.getUsername()) || !"123456".equals(user.getPassword())) {
System.out.println("用户名或者密码不正确!请检查!");
return;
}
System.out.println("登陆成功!角色为管理员!");
next.doHandle(user);
}
}

// 权限校验
class AuthHandler extends Handle {
@Override
public void doHandle(User user) {
if (!"admin".equals(user.getRole())) {
System.out.println("无权限操作!");
return;
}
System.out.println("角色为管理员,可以进行下一步操作!");
}
}
//登录流程
class LoginService{
public void login(User user){
Handle validateHandler = new ValidateHandler();
Handle loginHandler = new LoginHandler();
Handle authHandler = new AuthHandler();

validateHandler.next(loginHandler);
loginHandler.next(authHandler);

validateHandler.doHandle(user);
}
}

1.2 结合建造者模式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// handler抽象类
public abstract class Handler<T> {
protected Handler next;
// 返回handler方便链式操作
public Handler next(Handler next) {
this.next = next;
return next;
}
// 流程开始的方法
public abstract void doHandler(User user);
static class Builder<T> {
private Handler<T> head;
private Handler<T> tail;
public Builder<T> addHandler(Handler<T> handler) {
if (this.head == null) {
this.head = this.tail = handler;
return this;
}
this.tail.next(handler);
this.tail = handler;
return this;
}
public Handler<T> build() {
return this.head;
}
}
}
public class LoginService {
public void login(User user) {
Handler.Builder builder = new Handler.Builder();
builder.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler());
builder.build().doHandler(user);
}
}

1.3 总结

适用场景:

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 可动态指定一组对象处理请求。

优点:

  • 将请求与处理解耦。
  • 请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一级节点对象。
  • 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果。
  • 链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
  • 易于扩展新的请求处理类(节点),符合开闭原则。

缺点:

  • 责任链太长或者处理时间过长,会影响整体性能。
  • 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。