责任链模式的定义与特点
定义:
责任链模式(Chain Of Responsibility Pattern)是将链中每一个节点看做是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首段发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。属于行为型模式。
注意:责任链模式也叫职责链模式。
优点:
1.解耦。请求发起者和请求响应者进行解耦,链的创建由使用者(客户端)创建。
2.链路结构灵活。可以通过改变链路结构动态的新增或删减责任。
3.易扩展。可以根据需要增加新的请求处理类,满足开闭原则。
4.责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
5.责任链简化了对象的连接。每个对象只保持一个指向其后继者的引用,不需要保持其他所有处理者的引用,这避免了使用众多的 if 或者 if...else 语句。
缺点:
1.责任链太长或者处理时间过长,会影响整体性能。
2.如果节点对象存在循环引用时,会造成死循环,导致系统崩溃。
模式的角色
1.抽象处理者(Hanlder)角色:定义一个处理请求的接口,持有下一个处理类的引用。
2.具体处理者(Concrete Handler)角色:实现抽象处理者的方法,判断能否处理本次请求,否则将请求传给下一个处理者。
3.客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式的实现
1.创建抽象处理角色
/**
* 抽象处理角色:定义处理请求接口,持有下一个处理类的引用
*/
public abstract class Handler {
// 下一个处理类
private Handler next;
public void setNextHandler(Handler next){
this.next = next;
}
public Handler getNextHanler(){
return this.next;
}
// 处理请求抽象类
public abstract void handlerRequest(String request);
}
2.分别创建具体处理角色A,B
/**
* 具体处理者角色A:实现抽象处理者的方法,判断是否又能里处理请求
* 否则将请求传递给下一个处理者
*/
public class ConcreteHandlerA extends Handler {
@Override
public void handlerRequest(String request) {
if("A".equals(request)){
System.out.println("具体处理者 A 负责处理该请求");
}else{
// 如果处理不了,如果有下一个处理者,将请求传递个下一个处理者
if(getNextHanler() != null){
getNextHanler().handlerRequest(request);
}else{
System.out.println("没有人处理该请求了!");
}
}
}
}
/**
* 具体处理者角色B:实现抽象处理者的接口,判断是否能处理该请求
* 否则传递给下一个处理者
*/
public class ConcreteHandlerB extends Handler{
@Override
public void handlerRequest(String request) {
if("B".equals(request)){
System.out.println("具体处理者 B 负责处理该请求");
}else{
// 如果无法处理请求,如果有下一个处理者,将请求传递给下一个处理者
if(getNextHanler() != null){
getNextHanler().handlerRequest(request);
}else{
System.out.println("没有人处理该请求!");
}
}
}
}
3.测试
public static void main(String[] args) {
// 组装责任链
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
// 提交请求
handlerA.handlerRequest("B");
}
4.结果
具体处理者 B 负责处理该请求
策略模式应用实例(登陆校验)
不用设计模式可能我们的代码可能是这样写的
/**
* 会员类
*/
public class Member {
// 用户名
private String loginName;
// 密码
private String loginPass;
// 角色
private String roleName;
public Member(String loginName, String loginPass, String roleNameName){
this.loginName = loginName;
this.loginPass = loginPass;
this.roleName = roleNameName;
}
// get set 省略....
/**
* 业务逻辑类
*/
public class MemberService {
// 用户操作一系列校验
public void login(String loginName,String loginPass){
if("".equals(loginName) || "".equals(loginPass)){
System.out.println("用户名或者密码不能为空");
return ;
}
System.out.println("用户名和密码不为空,可以往下执行");
// 检查用户是否存在
Member member = checkExists(loginName, loginPass);
if(null == member){
System.out.println("用户不存在");
return;
}
if(!"管理员".equals(member.getRoleName())){
System.out.println("您不是管理员,没有操作权限");
}
System.out.println("允许操作");
}
// 检查用户是否存在
private Member checkExists(String loginName,String loginPass,String roleName){
if(!"admin".equals(loginName) || !"admin".equals(loginPass)){
return null;
}
Member member = new Member(loginName,loginPass,roleName);
return member;
}
}
登陆校验
public static void main(String[] args) {
MemberService ms = new MemberService();
ms.login("admin","admin","xxx");
}
结果
用户名和密码不为空,可以往下执行
您是管理员
允许操作
虽然完成了功能,但是耦合性很强,代码臃肿,难扩展,不符合开闭原则
使用责任链模式重构
创建抽象处理类,定义具体类要实现的接口,并持有下一个处理类的引用
/**
* 抽象处理:定义具体类要实现的接口,并持有下一个处理类引用
*/
public abstract class Handler {
// 下一个处理引用
private Handler next;
public void setNext(Handler next){
this.next = next;
}
public Handler getNext(){
return next;
}
// 处理接口
public abstract void doHandler(Member member);
}
分别创建具体处理类 ValidateHandler,LoginHandler,AuthHandler 实现抽象处理类的接口,分别做非空校验,用户校验,权限校验
/**
* 具体处理者:非空验证逻辑
*/
public class ValidateHandler extends Handler{
@Override
public void doHandler(Member member) {
if("".equals(member.getLoginName()) || "".equals(member.getLoginPass())){
System.out.println("用户名或者密码不能为空");
return ;
}
System.out.println("用户名和密码不为空,可以往下执行");
// 调用下一个处理类
this.getNext().doHandler(member);
}
}
/**
* 具体处理类:用户名密码校验逻辑
*/
public class LoginHandler extends Handler{
@Override
public void doHandler(Member member) {
// 检查用户是否存在
Member m = checkExists(member.getLoginName(), member.getLoginPass(), member.getRoleName());
if(null == m){
System.out.println("用户不存在");
return;
}
// 调用下一个处理类
this.getNext().doHandler(m);
}
// 检查用户是否存在
private Member checkExists(String loginName,String loginPass,String roleName){
if(!"admin".equals(loginName) || !"admin".equals(loginPass)){
return null;
}
Member member = new Member(loginName,loginPass,roleName);
return member;
}
}
/**
* 具体处理类:权限校验
*/
public class AuthHandler extends Handler{
@Override
public void doHandler(Member member) {
if(!"管理员".equals(member.getRoleName())){
System.out.println("您不是管理员,没有操作权限");
return ;
}
System.out.println("您是管理员");
System.out.println("允许操作");
}
// AuthHandler 没有下一个处理类了
}
业务逻辑类 MemberService
/**
* 业务逻辑类
*/
public class MemberService {
public void login(String loginName,String loignPass,String roleName){
// 分控校验逻辑
Handler validateHandler = new ValidateHandler();
// 用户名密码校验逻辑
Handler loginHandler = new LoginHandler();
// 权限校验逻辑
Handler authHandler = new AuthHandler();
// 非空校验完毕是 用户名密码校验
validateHandler.setNext(loginHandler);
// 用户名密码校验完毕是 权限校验
loginHandler.setNext(authHandler);
// 权限校验完毕,没有下一个处理类了 从非空校验头链开始调用
validateHandler.doHandler(new Member(loginName,loignPass,roleName));
}
}
调用测试
public static void main(String[] args) {
MemberService ms = new MemberService();
ms.login("admin","admin","管理员");
}
结果
用户名和密码不为空,可以往下执行
您是管理员
允许操作
使用责任链模式重构够后代码逻辑非常清晰,扩展方便,只需要增加新的算法类即可,符合开闭原则。但是此时的代码如何责任链类非常多的话,需要一直 next,next,next ...... 设置下一个责任处理类比较繁琐而且责任的关系维护复杂,怎么办呢?使用建造者模式优化一下
修改抽象处理类(Handler )代码
/**
* 抽象处理:定义具体类要实现的接口,并持有下一个处理类引用
*/
public abstract class Handler <T>{
// 下一个处理引用
private Handler next;
public void setNext(Handler next){
this.next = next;
}
public Handler getNext(){
return next;
}
// 处理接口
public abstract void doHandler(Member member);
// 双向链表
public static class Builder<T>{
// 头部处理类
private Handler<T> head;
// 尾部处理类
private Handler<T> tail;
public Builder<T> addHandler(Handler handler){
// 首次进入头部 尾部 都等于 handler\
if(this.head == null){
this.head = this.tail = handler;
return this;
}
// 下一次不等于 null 从尾部开始追加
this.tail.setNext(handler);
// 把尾部替换一下
this.tail = handler;
return this;
}
// build 返回头部 从头部开始执行
public Handler<T> build(){
return this.head;
}
}
}
修改业务类(MemberService )代码
/**
* 业务逻辑类
*/
public class MemberService {
public void login(String loginName,String loignPass,String roleName){
// 依次添加需要的校验逻辑,不需要的不添加,可以灵活删减责任,避免了众多的 if else ...
Handler.Builder handler = new Handler.Builder();
handler.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler());
// 怎么添加就怎么执行
// 从头部开始执行
handler.build().doHandler(new Member(loginName,loignPass,roleName));
}
}
其他代码不变,最终测试一下结果是一样的,但是结构非常的清晰,责任链的关系维护简单。
测试
public static void main(String[] args) {
MemberService ms = new MemberService();
ms.login("admin","admin","管理员");
}
结果
用户名和密码不为空,可以往下执行
您是管理员
允许操作
网友评论