1、责任链模式
在面向对象的开发中,往往力求对象之间保持松耦合,确保对象各自的责任最小化、具体化。其实我们在学习Servlet的时候,经常用Filter做拦截器,比如:拦截登录请求
public class FilterDemo implements Filter{
/**
* 用于拦截请求
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("user");
// 如果等于 null,说明还没有登录:则不允许访问私人页面
if (user == null) {
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
} else {
// 让程序继续往下访问用户的目标资源:如果没有其他的过滤器,将访问请求的资源;如果有过滤器则继续进入其他过滤器
chain.doFilter(request,response);
}
}
}
这里的chain.doFilter的链式处理,即把所有的Filter都放在FilterChain中,然后依次执行每个过滤器,有符合条件的就处理,直到没有其他过滤器,就访问请求的资源。这就是责任链模式的运用,一个链式的处理流程。
这种模式在现实生活中也非常常见,比如:请假审批流程、报销审批流程、项目进度流程等等都可以考虑使用责任链模式来实现。
1.1、什么是责任链模式
-
定义
责任链模式是一种行为设计模式,为了避免发送者与多个请求处理者耦合在一起,将能够处理同一类请求的对象连成一条链,所提交的请求沿着处理程序链传递,如果能处理则处理,如果不能处理则传递给链上的下一个对象。
责任链模式的结构:
1)抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
2)基础处理者(Base Handler)角色:可选类/抽象类,可以在其中放置所有处理程序类共有的代码。
3)具体处理者(Concrete Handler)角色:实现抽象处理者或基础处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
4)客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式的意图在于:将特定行为转换为处理程序的独立对象,以解除请求的发送者与接受者之间的耦合。
也就是说请求只需要发送到责任链上,无须关心请求的处理细节和请求的传递过程,请求会自动处理。
1.2、责任链模式的优缺点
-
优点
1)可以控制请求处理的顺序;
2)将发送者与接收者解耦,降低了对象之间的耦合度,简化了对象之间的连接,避免了使用众多的if···else语句,符合单一职责原则;
3)符合开闭原则,增强了系统的可扩展性。可以根据需要增加新的请求处理类。
-
缺点
1)不能保证每个请求一定被处理。
2)对于较长的责任链,涉及对象过多,会降低系统的性能;
3)将if···else语句中的中的特定行为都转换为对象,增加了类的数量,同时也增加了系统的复杂度。
1.3、创建方式
我们就以公司请假审批流程为例。员工请假1天,组长审批即可;请假2天,部门经理审批即可;请假3-7天,项目总监审批即可;请假7天以上,需要总经理审批。
不用责任链,可能会这样写:
public class LeaveDemo {
public boolean askForLeave(int days){
if(1 == days){
//processGroupLeader();
System.out.println("组长同意");
return true;
}else if(2 == days){
//processDpManager();
System.out.println("部门经理同意");
return true;
}else if(3>=days && days<=7){
//processCfInspector();
System.out.println("项目总监同意");
return true;
}else{
//processGeneralManager();
System.out.println("总经理同意");
return true;
}
}
}
使用责任链模式。
1)抽象处理者(Handler)角色
/**
* 抽象处理者Handler
*/
public interface LeaderChain {
public abstract void setNextChain(LeaderChain nextChain);
public abstract void handleRequest(int days);
}
2)具体处理者(Concrete Handler)角色
//组长
public class GroupLeader implements LeaderChain{
private LeaderChain nextChain;
//这部分可以提取BaseHandle
@Override
public void setNextChain(LeaderChain nextChain) {
this.nextChain=nextChain;
}
@Override
public void handleRequest(int days) {
if(1==days){
System.out.println("组长同意");
}else{
//交给上一级处理
this.nextChain.handleRequest(days);
}
}
}
//部门经理
public class DpManager implements LeaderChain {
private LeaderChain nextChain;
@Override
public void setNextChain(LeaderChain nextChain) {
this.nextChain=nextChain;
}
@Override
public void handleRequest(int days) {
if(days==2){
System.out.println("部门经理同意");
}else{
//交给上一级处理
this.nextChain.handleRequest(days);
}
}
}
//项目总监
public class CfInspector implements LeaderChain {
private LeaderChain nextChain;
@Override
public void setNextChain(LeaderChain nextChain) {
this.nextChain=nextChain;
}
@Override
public void handleRequest(int days) {
if(3<=days && days<=7){
System.out.println("项目总监同意");
}else{
//交给上一级处理
this.nextChain.handleRequest(days);
}
}
}
//总经理
public class GeneralManager implements LeaderChain {
private LeaderChain nextChain;
@Override
public void setNextChain(LeaderChain nextChain) {
this.nextChain=nextChain;
}
@Override
public void handleRequest(int days) {
if(days>7 && days<365){
System.out.println("总经理同意");
}
if(nextChain==null){
System.out.println("还是直接辞职吧");
}
}
}
3)客户类(Client)角色
public class Client {
public static void main(String[] args) {
//请假1天
Leaveapplication(1);
//请假2天
Leaveapplication(2);
//请假3天
Leaveapplication(3);
//请假一年
Leaveapplication(365);
}
//请假流程组装
public static void Leaveapplication(int days){
LeaderChain gl = new GroupLeader();
LeaderChain dp = new DpManager();
LeaderChain cf = new CfInspector();
LeaderChain gm = new GeneralManager();
gl.setNextChain(dp);
dp.setNextChain(cf);
cf.setNextChain(gm);
//提交请求
gl.handleRequest(days);
}
}
输出结果:
此时的UML关系图:
如果我们在总经理前面再加一个副总经理,不需要像之前的if...else中要修改代码的逻辑。
1.4、总结及建议
在运用责任链模式时,客户端不必事先知道对象集合中的哪个对象可以提供自己需要的服务。当客户端发出请求后,该请求会沿着职责链转发请求,直到找到能够提供该服务的对象为止。这就实现了请求者与执行者间的解耦。
应用场景:
1)如果希望以各种方式处理不同类型的请求,并且不知道请求的确切类型时,可以使用责任链模式;
2)当以特定顺序执行多个处理程序时,可以使用 模式;(由于你可以按某种顺序链组合,所有的请求都会按你指定的计划执行);
3)当你的应用程序可能需要动态指定一组对象处理请求时,或者希望添加新的处理者时,可以使用责任链模式;
JDK中责任链模式的应用:
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
try-catch代码块