Java责任链模式
本文介绍广泛使用的行为模式————责任链模式。
1. 概述
责任链模式有一个源头命令对象和一系列处理对象组成。链中每个处理对象负责处理特定类型命令,处理完成后交给下一个处理对象。
责任链模式一般用于:
- 解耦命令发送者和接受者
- 处理时选择处理策略
下面通过示例进行说明。
2. 示例
示例使用责任链处理认证请求。输入认证提供者在该场景下是命令,每个认证处理器是独立处理对象。
首先定义处理器抽象类:
public abstract class AuthenticationProcessor {
// 责任链中下一个处理器对象
public AuthenticationProcessor nextProcessor;
public AuthenticationProcessor(AuthenticationProcessor nextProcessor) {
this.nextProcessor = nextProcessor;
}
public abstract boolean isAuthorized(AuthenticationProvider authProvider);
}
后面需要实现具体的处理类。现在我们看命令提供者,该场景下就是认证请求,首先定义接口:
public interface AuthenticationProvider {
}
为了简单,我们假设有好几种类型认证请求:
// 用户名和密码
public class UsernamePasswordProvider implements AuthenticationProvider {
}
// 安全认证,用于sso
public class SamlAuthenticationProvider implements AuthenticationProvider {
}
// OAuth
public class OAuthTokenProvider implements AuthenticationProvider {
}
对于不同类型认证请求,有相应的处理器。
public class OAuthAuthenticationProcessor extends AuthenticationProcessor {
public OAuthAuthenticationProcessor(AuthenticationProcessor nextProcessor) {
super(nextProcessor);
}
@Override
public boolean isAuthorized(AuthenticationProvider authProvider) {
if (authProvider instanceof OAuthTokenProvider) {
return Boolean.TRUE;
} else if (nextProcessor != null) {
return nextProcessor.isAuthorized(authProvider);
} else {
return Boolean.FALSE;
}
}
}
public class UsernamePasswordAuthenticationProcessor extends AuthenticationProcessor {
public UsernamePasswordAuthenticationProcessor(AuthenticationProcessor nextProcessor) {
super(nextProcessor);
}
@Override
public boolean isAuthorized(AuthenticationProvider authProvider) {
if (authProvider instanceof UsernamePasswordProvider) {
return Boolean.TRUE;
} else if (nextProcessor != null) {
return nextProcessor.isAuthorized(authProvider);
} else {
return Boolean.FALSE;
}
}
}
我们看到逻辑都一样,仅处理特定类型的输入请求,否则流转至下一个处理器或退出。
这里我们创建了两个具体处理器UsernamePasswordProcessor 和 OAuthProcessor,每一个都覆写isAuthorized 方法处理特定类型请求。测试代码如下:
public class ChainOfResponsibilityTest {
private static AuthenticationProcessor getChainOfAuthProcessor() {
AuthenticationProcessor oAuthProcessor = new OAuthProcessor(null);
return new UsernamePasswordProcessor(oAuthProcessor);
}
@Test
public void givenOAuthProvider_whenCheckingAuthorized_thenSuccess() {
AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor();
assertTrue(authProcessorChain.isAuthorized(new OAuthTokenProvider()));
}
@Test
public void givenSamlProvider_whenCheckingAuthorized_thenSuccess() {
AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor();
assertFalse(authProcessorChain.isAuthorized(new SamlTokenProvider()));
}
}
首先创建认证处理链:UsernamePasswordProcessor -> OAuthProcessor。第一个测试通过,第二个失败。
第一个测试UsernamePasswordProcessor 检查请求类型是UsernamePasswordProvider,不是期望类型,接着委托给下一个处理器OAuthProcessor,OAuthProcessor负责处理该类型请求,因此测试通过。第二个测试链中没有更多处理器,测试失败。
3. 责任链模式适用场景分析
实例责任链模式需要了解几条重要原则:
- 每个处理器负责处理特定类型命令,我们实例中所有处理器都实现自己isAuthorized方法。
- 每个处理器都有下一个处理器的引用,示例中UsernamePasswordProcessor 引用 OAuthProcessor。
- 每个处理器负责委托下一个处理,避免丢弃命令。我们示例中如果输入请求是SamlProvider 类型实例,那么请求得不到处理认证失败。
- 处理器不能形成递归循环:示例中责任链是UsernamePasswordProcessor -> OAuthProcessor,如果后面有增加UsernamePasswordProcessor 则造成UsernamePasswordProcessor-> OAuthProcessor -> UsernamePasswordProcessor递归循环。
Java中责任链模式应用很普遍。几乎每天我们都在使用,经典示例即Servlet Filters,使用多个过滤器处理HTTP请求,虽然这种场景是每个过滤器都处理请求。
让我们看看一段代码加深理解:
public class CustomFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// process the request
// pass the request (i.e. the command) along the filter chain
chain.doFilter(request, response);
}
}
上面代码中FilterChain的doFilter方法是负责传递请求给下一个过滤器。
到目前为止我们已经看了责任链模式的用途,但其也有些不足:
- 可能造成问题:如果一个处理器调用下一个处理器失败会造成命令丢弃;如果处理器调用错误处理器会造成链变成环。
- 可能创建深度堆栈跟踪影响性能。
- 多个处理器导致重复代码,增加维护成本。
4. 总结
本文介绍了责任链模式及其优缺点,通过处理认证请求场景进行示例说明。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/106588268