一、定义
责任链模式(Chain of Responseiblibity Pattrern) 是将链中每一个节点看做是一个对象, 每个节点处理的请求均不同, 且内部自动维护一个下一节点对象. 当一个请求从链式的首端发出时, 会沿着链的路径依次传递给每一个节点对象, 直至有对象处理这个请求为止.
属于行为型设计模式
二、适用场景
- 多个对象可以处理同一请求, 但具体由哪个对象处理则在运行时动态决定.
- 在不明确指定接收者的情况下, 向多个对象中的一个提交一个请求.
- 可动态指定一组对象处理请求.
三、java代码简单案例
此处使用用户登录及认证做一个简单案例
使用责任链模式之前
/**
* 用户实体类
*/
@Data
public class User {
private String loginName;
private String loginPass;
private String roleName;
public User(String loginName, String loginPass) {
this.loginName = loginName;
this.loginPass = loginPass;
}
@Override
public String toString() {
return "Member{" +
"loginName='" + loginName + '\'' +
", loginPass='" + loginPass + '\'' +
", roleName='" + roleName + '\'' +
'}';
}
}
/**
* 用户业务实现类
*/
public class UserService {
public void login(String loginName,String loginPass){
if(StringUtils.isEmpty(loginName) ||
StringUtils.isEmpty(loginPass)){
System.out.println("用户名和密码为空");
return;
}
System.out.println("用户名和密码不为空,可以往下执行");
User user = checkExists(loginName,loginPass);
if(null == user){
System.out.println("用户不存在");
return;
}
System.out.println("登录成功!");
if(!"管理员".equals(user.getRoleName())){
System.out.println("您不是管理员,没有操作权限");
return;
}
System.out.println("允许操作");
}
private User checkExists(String loginName, String loginPass){
User user = new User(loginName,loginPass);
user.setRoleName("管理员");
return user;
}
public static void main(String[] args) {
UserService service = new UserService();
service.login("tom","666");
}
}
以上, 在实现用户登录业务逻辑的时候, 各种校验于代码中... 可能还会有其他的业务校验, 就会造成代码长度过大, 非常复杂.
使用责任链模式之后
/**
* 业务处理接口, 结合了建造者模式
*/
public abstract class Handler<T> {
protected Handler<T> next;
public void next(Handler next){ this.next = next;}
public abstract void doHandler(User user);
public static class Builder<T>{
private Handler<T> head;
private Handler<T> tail;
public Builder<T> addHandler(Handler handler){
//do {
if (this.head == null) {
this.head = this.tail = handler;
return this;
}
this.tail.next(handler);
this.tail = handler;
//}while (false);//真正框架中,如果是双向链表,会判断是否已经到了尾部
return this;
}
public Handler<T> build(){
return this.head;
}
}
}
/**
* Handler实现类, 该Handler用于处理登录成功后的逻辑
*/
public class LoginHandler extends Handler {
public void doHandler(User user) {
System.out.println("登录成功!准备跳转首页...");
// 登录成功后的业务逻辑......
if(null != next) {
next.doHandler(user);
}
}
}
/**
* 权限认证Handler实现类
*/
public class AuthHandler extends Handler {
public void doHandler(User user) {
if(!"管理员".equals(user.getRoleName())){
System.out.println("您不是管理员,没有操作权限");
return;
}
System.out.println("允许操作");
if(null != next) {
next.doHandler(user);
}
}
}
/**
* 用户名密码校验
*/
public class ValidateHandler extends Handler {
public void doHandler(User user) {
if(StringUtils.isEmpty(user.getLoginName()) ||
StringUtils.isEmpty(user.getLoginPass())){
System.out.println("用户名和密码为空");
return;
}
System.out.println("用户名和密码不为空,可以往下执行");
if(null != next) {
next.doHandler(user);
}
}
}
/**
* 用户Service层
*/
public class UserService {
public void login(String loginName,String loginPass){
Handler.Builder builder = new Handler.Builder();
builder.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler());
User user = new User(loginName, loginPass);
user.setRoleName("管理员");
builder.build().doHandler(user);
//用过Netty的人,肯定见过
}
}
测试类
public class Test {
public static void main(String[] args) {
UserService userService = new UserService();
userService.login("tom","666");
}
}
测试结果
------------------------------------------------------
用户名和密码不为空,可以往下执行
登录成功!
允许操作
------------------------------------------------------
四、优点
- 将请求与处理解耦.
- 请求矗立着(节点对象) 只需关注自己感兴趣的请求进行处理即可, 对不感兴趣的请求, 直接转发给下一级节点对象.
- 具备链式传递处理请求功能, 请求发送者无需知晓链路结构, 只需等待请求处理结果.
- 链路结构灵活, 可以通过改变链路结构动态地新增或删减责任.
- 易于扩展新的请求处理类(节点), 符合开闭原则.
五、缺点
- 责任链太长或者处理时间过长, 会影响整体性能,
- 如果节点对象存在循环引用时, 会造成死循环, 导致系统崩溃.