责任链(Chain of Responsibility):为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
责任链模式中的角色:
- 抽象处理者(Handle): 定义一个处理请求的接口, 包含处理方法和下一个处理对象
- 具体处理者(Concrete Handler): 实现处理请求的方法, 判断是否能处理该请求, 如果能,则处理, 如果不能, 则将请求传递给下一个处理者
- 客户端(Client): 用户创建处理链, 不处理具体请求, 只是将请求传递给处理链中的第一个处理者
责任链模式的优缺点:
优点:
- 降低了对象之间的耦合度: 请求的发送者和请求的处理者不需要知道彼此的详细信息, 请求的发送者只需要将请求发送出去, 请求的处理者也不知道链中的结构, 只需要保存对下一个处理者的应用, 大大降低了对象之间的耦合度.
- 增加了系统的可拓展性: 如果要增加责任链中的处理器, 只需要实现处理接口, 满足开闭原则
- 增加了系统的灵活性: 可以随时增加, 修改, 调整处理请求的结构.
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句
缺点:
不能保证每个请求都会被处理: 一个请求可能到了链的末位都得不到处理或者因为没有正确配置而得不到处理.
责任链模式结构图
Handler: 定义一个处理请求的接口
public abstract class Handler {
protected Handler nextHandler;
public Handler() {
}
public Handler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handlerRequest(int requestId);
}
ConcreteHandler: 具体的处理请求类
public class ConcreteHandler1 extends Handler{
public ConcreteHandler1() {
super();
}
public ConcreteHandler1(Handler nextHandler) {
super(nextHandler);
}
@Override
public void handlerRequest(int requestId) {
if (requestId > 0 && requestId < 10) {
System.out.println("请求ID大于0,小于10, 由ConcreteHandler1处理");
} else if (nextHandler != null) {
nextHandler.handlerRequest(requestId);
}
}
}
public class ConcreteHandler2 extends Handler{
public ConcreteHandler2() {
super();
}
public ConcreteHandler2(Handler nextHandler) {
super(nextHandler);
}
@Override
public void handlerRequest(int requestId) {
if (requestId >= 10 && requestId < 20) {
System.out.println("请求ID大于等于10, 小于20, 由ConcreteHandler2处理, requestId: " + requestId);
} else if (nextHandler != null) {
nextHandler.handlerRequest(requestId);
}
}
}
public class ConcreteHandler3 extends Handler{
public ConcreteHandler3() {
super();
}
public ConcreteHandler3(Handler nextHandler) {
super(nextHandler);
}
@Override
public void handlerRequest(int requestId) {
if (requestId >= 20) {
System.out.println("请求ID大于等于20, 由ConcreteHandler3处理, requestId: " + requestId);
} else if (nextHandler != null) {
nextHandler.handlerRequest(requestId);
}
}
}
Client: 创建责任链.
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
List<Integer> requestIdList = Arrays.asList(2, 12, 32, 8, 20, 16, 33);
for (Integer requestId : requestIdList) {
handler1.handlerRequest(requestId);
}
}
}
开发案例
需求说明:
用户做完报告之后, 将报告发布到系统中指定的专区,用户可以在系统首页查看已经发布的报告。
系统角色: 系统管理员、项目管理员、普通用户
- 系统管理员: 拥有所有报告的访问权限
- 专区管理员: 拥有报告编号在10以下的报告权限
- 普通用户: 拥有报告编号在10以上的访问权限
/**
* 用户对报告的访问
* @author wtkk
*/
public abstract class UserAccessReport {
protected UserAccessReport userAccessReport;
public UserAccessReport(UserAccessReport userAccessReport) {
this.userAccessReport = userAccessReport;
}
public void setUserAccessReport(UserAccessReport userAccessReport) {
this.userAccessReport = userAccessReport;
}
/**
* 判断用户对报告是否有访问权限
* @param userName 用户名称
* @param rptId 报告id
* @return 对报告是否有权限
*/
abstract Boolean execute(String userName, int rptId);
}
/**
* 系统管理员对报告的访问权限
* @author wtkk
*/
public class SystemManagerUserAccessReport extends UserAccessReport {
public SystemManagerUserAccessReport(UserAccessReport userAccessReport) {
super(userAccessReport);
}
@Override
public Boolean execute(String userName, int rptId) {
if ("系统管理员".equals(userName)) {
System.out.println("系统管理员:有权限访问报告:" + rptId);
return true;
} else {
if (userAccessReport != null) {
setUserAccessReport(userAccessReport);
return userAccessReport.execute(userName, rptId);
}
return false;
}
}
}
/**
* 项目管理员对报告的访问权限
* @author wtkk
*/
public class ProjectManagerUserAccessReport extends UserAccessReport {
public ProjectManagerUserAccessReport(UserAccessReport userAccessReport) {
super(userAccessReport);
}
@Override
public Boolean execute(String userName, int rptId) {
if ("项目管理员".equals(userName)) {
if (rptId < 10) {
System.out.println("项目管理员:有权限访问报告:" + rptId);
return true;
}
System.out.println("项目管理员:无权限访问报告:" + rptId);
return false;
} else {
if (userAccessReport != null) {
setUserAccessReport(userAccessReport);
return userAccessReport.execute(userName, rptId);
}
return false;
}
}
}
/**
* 普通用户对报告的访问权限
* @author wtkk
*/
public class NormalUserAccessReport extends UserAccessReport {
public NormalUserAccessReport(UserAccessReport userAccessReport) {
super(userAccessReport);
}
@Override
public Boolean execute(String userName, int rptId) {
if ("普通用户".equals(userName)) {
if (rptId >= 10) {
System.out.println("普通用户:有权限访问报告:" + rptId);
return true;
}
System.out.println("普通用户:无权限访问报告:" + rptId);
return false;
} else {
if (userAccessReport != null) {
setUserAccessReport(userAccessReport);
return userAccessReport.execute(userName, rptId);
}
return false;
}
}
}
/**
* 封装访问客户端
* @author wtkk
*/
public class AccessReportClient {
public Boolean execute(String userName, int rptId) {
// 构建责任链
UserAccessReport normalUserAccessReport = new NormalUserAccessReport(null);
UserAccessReport projectManagerUserAccessReport = new ProjectManagerUserAccessReport(normalUserAccessReport);
UserAccessReport systemManagerUserAccessReport = new SystemManagerUserAccessReport(projectManagerUserAccessReport);
// 执行
return systemManagerUserAccessReport.execute(userName, rptId);
}
}
/**
* 责任链模式:
* 需求说明:用户做完报告之后, 将报告发布到系统中指定的专区,用户可以在系统首页查看已经发布的报告。
* 系统角色: 系统管理员、项目管理员、普通用户
* 系统管理员: 拥有所有报告的访问权限
* 专区管理员: 拥有报告编号在10以下的报告权限
* 普通用户: 拥有报告编号在10以上的访问权限
*/
public class App {
public static void main(String[] args) {
// 构建责任链
AccessReportClient client = new AccessReportClient();
client.execute("系统管理员", 1);
client.execute("系统管理员", 11);
client.execute("系统管理员", 21);
client.execute("项目管理员", 1);
client.execute("项目管理员", 11);
client.execute("项目管理员", 21);
client.execute("普通用户", 1);
client.execute("普通用户", 11);
client.execute("普通用户", 21);
}
}