1. 责任链模式定义
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
2. 使用场景
- 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
3.责任链模式的组成
从UML类图可以看到,责任链模式包含三种角色:
- 抽象处理者Handler: 定义一个处理请求的接口方法,并维护下一个处理节点Hadnler的引用。
- 具体处理者ConcreteHandler :对请求进行处理,如果不能处理,则转发给下一个处理者
- 客户类角色:创建请求处理链(具体的请求处理者),并设置请求处理链的关系,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
4. 责任链案例
利用责任链模式完成一个数据校验,首先创建一个需要进行校验的实体类Member(getter setter 省略 )
package com.lchtest.pattern.responsibilitychain.auth;
public class Member {
private String loginName;
private String loginPass;
private String roleName;
public Member(String loginName, String loginPass) {
this.loginName = loginName;
this.loginPass = loginPass;
}
}
如果不使用责任链模式,大概率会if走天下:
package com.lchtest.pattern.responsibilitychain.auth.old;
import com.lchtest.pattern.responsibilitychain.auth.Member;
import org.apache.commons.lang.StringUtils;
/**
* 用户登录校验- low的写法——纯if判断
*/
public class MemberService {
public void login(String loginName, String loginPass) {
if (StringUtils.isEmpty(loginName) || StringUtils.isEmpty(loginPass)) {
System.out.println("用户名和密码为空");
return;
}
System.out.println("用户名和密码不为空,可以往下执行");
Member member = checkExists(loginName, loginPass);
if (null == member) {
System.out.println("用户不存在");
return;
}
System.out.println("登录成功!");
if (!"管理员".equals(member.getRoleName())) {
System.out.println("您不是管理员,没有操作权限");
return;
}
System.out.println("允许操作");
}
private Member checkExists(String loginName, String loginPass) {
Member member = new Member(loginName, loginPass);
member.setRoleName("管理员");
return member;
}
public static void main(String[] args) {
MemberService service = new MemberService();
service.login("tom", "666");
}
}
上面这段代码主要是完成登录前的数据校验逻辑,但是这种代码与我们真正的业务逻辑代码搀杂在一起会显得非常臃肿,而如果使用责任链模式,可以将这些检查步骤放到独立的类中,使得编码时专注于业务逻辑处理,使用责任链模式优化代码如下:
- 首先创建一个责任链的抽象,两个要点:1. 它要持有自身对象的引用,作为nextHandler 2.定义抽象的请求处理方法
package com.lchtest.pattern.responsibilitychain.auth.optimize;
import com.lchtest.pattern.responsibilitychain.auth.Member;
public abstract class Handler {
protected Handler nextHandler;
public void next(Handler handler){
this.nextHandler = handler;
}
// 抽象方法,每个具体的handler处理一种验证
public abstract void validate(Member member);
}
- 创建处理请求的具体的Handler :
登录用户名非空校验类LoginNameValidateHandler ,登录校验类LoginStateValidateHandler 和用户权限校验类PermissionAuthHandler, 每个具体的handler都继承 Handler
package com.lchtest.pattern.responsibilitychain.auth.optimize;
import com.lchtest.pattern.responsibilitychain.auth.Member;
import org.apache.commons.lang.StringUtils;
public class LoginNameValidateHandler extends Handler {
@Override
public void validate(Member member) {
if (StringUtils.isEmpty(member.getLoginName()) || StringUtils.isEmpty(member.getLoginPass())) {
System.out.println("用户名和密码为空");
return;
}
System.out.println("LoginNameValidateHandler check ok! 用户名和密码不为空,可以往下执行");
// 让下一个handler执行
nextHandler.validate(member);
}
}
package com.lchtest.pattern.responsibilitychain.auth.optimize;
import com.lchtest.pattern.responsibilitychain.auth.Member;
public class LoginStateValidateHandler extends Handler {
@Override
public void validate(Member member) {
System.out.println("LoginStateValidateHandler check ok! 登录成功!");
member.setRoleName("管理员");
nextHandler.validate(member);
}
}
package com.lchtest.pattern.responsibilitychain.auth.optimize;
import com.lchtest.pattern.responsibilitychain.auth.Member;
public class PermissionAuthHandler extends Handler {
@Override
public void validate(Member member) {
if (!"管理员".equals(member.getRoleName())) {
System.out.println("非管理员,没有操作权限");
return;
}
System.out.println("PermissionAuthHandler check ok! 允许操作");
// 权限检查完了,后面没有handler了;
// nextHandler.validate(member);
}
}
- 创建客户类,设置各个责任链的节点关系,将责任链串联起来,并启动责任链头节点处理请求,这里放到原来的MemberService里面即可
package com.lchtest.pattern.responsibilitychain.auth.optimize;
import com.lchtest.pattern.responsibilitychain.auth.Member;
/**
* 用户登录校验- 责任链写法
*/
public class MemberService {
public void login(String loginName, String loginPass) {
Handler validateHandler = new LoginNameValidateHandler();
Handler loginHandler = new LoginStateValidateHandler();
Handler authHandler = new PermissionAuthHandler();
// 设置责任链关系 这里有个缺点,如果handler的个数非常多,这里就显得很繁琐了,可以采用建造者模式改进
validateHandler.next(loginHandler);
loginHandler.next(authHandler);
validateHandler.validate(new Member(loginName,loginPass));
}
}
- 测试:
package com.lchtest.pattern.responsibilitychain.auth.optimize;
public class Test {
public static void main(String[] args) {
MemberService memberService = new MemberService();
memberService.login("jack", "123");
}
}
在上面的优化中,MemberService中前一个handler要设置下一个要处理请求的handler,如果handler的个数非常多, 还可以进一步使用建造者模式来优化为链式调用:
- 将Handler进行改造,建造者模式要构建的是节点处理者,可以把Builder作为Handler的静态内部类,每个具体的Handler的链式组装也放到Hadnler的Builder中,无需像之前一样放在memberservice中设置责任链顺序,因此可以把next()方法设置为私有,使得Handler更加内聚
package com.lchtest.pattern.responsibilitychain.auth.builderchain;
import com.lchtest.pattern.responsibilitychain.auth.Member;
public abstract class Handler<T> {
protected Handler<T> nextHandler;
private void next(Handler<T> handler) { //这里由protected改为private,不对外暴露
this.nextHandler = handler;
}
// 抽象方法,每个具体的handler处理一种验证
public abstract void validate(Member member);
protected static class Builder<T> {
private Handler<T> head;
private Handler<T> tail;
public Builder<T> add(Handler<T> handler) {
if (this.head == null) {
this.head = this.tail = handler;
return this;
}
// 设置当前handler的下一个过滤器节点
this.tail.next(handler);
// 将过滤器链的tail移动到刚添加的新过滤链节点,也就是add方法的入参
this.tail = handler;
return this;
}
public Handler<T> build() {
return this.head; // 返回过滤器链的头部节点
}
}
}
- 对MemberService进行改造:
package com.lchtest.pattern.responsibilitychain.auth.builderchain;
import com.lchtest.pattern.responsibilitychain.auth.Member;
/**
* 用户登录校验- 责任链写法
*/
public class MemberService {
public void login(String loginName, String loginPass) {
// Handler<T> validateHandler = new ValidateHandler();
// Handler<T> loginHandler = new LoginHandler();
// Handler<T> authHandler = new AuthHandler();
// 设置责任链关系
// validateHandler.next(loginHandler);
// loginHandler.next(authHandler);
// validateHandler.doHandler(new Member(loginName,loginPass));
// 通过建造者模式创建过滤器链
Handler.Builder<Handler> builder = new Handler.Builder<>();
Handler executeHandler = builder.add(new LoginNameValidateHandler())
.add(new LoginStateValidateHandler())
.add(new PermissionAuthHandler()).build();
executeHandler.validate(new Member(loginName, loginPass));
}
}