Skip to main content
 首页 » 编程设计

Java责任链模式

2022年07月19日180shihaiming

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
阅读延展