1. 소개

이 기사에서는 널리 사용되는 행동 설계 패턴책임 사슬에 대해 살펴보겠습니다 .

이전 기사 에서 더 많은 디자인 패턴을 찾을 수 있습니다 .

2. 책임의 사슬

Wikipedia 는 책임 사슬을 "명령 개체의 소스와 일련의 처리 개체"로 구성된 디자인 패턴으로 정의합니다.

체인의 각 처리 개체는 특정 유형의 명령을 담당하고 처리가 완료되면 명령을 체인의 다음 프로세서로 전달합니다.

책임 사슬 패턴은 다음에 유용합니다.

  • 명령의 발신자와 수신자를 분리
  • 처리 시간에 처리 전략 선택

패턴의 간단한 예를 살펴보겠습니다.

3. 예시

우리는 책임 사슬을 사용하여 인증 요청을 처리하기 위한 사슬을 만들 것입니다.

따라서 입력 인증 Provider는 명령 이 되고 각 인증 프로세서는 별도의 프로세서 개체가 됩니다.

먼저 프로세서에 대한 추상 기본 클래스를 생성해 보겠습니다.

public abstract class AuthenticationProcessor {

    public AuthenticationProcessor nextProcessor;
    
    // standard constructors

    public abstract boolean isAuthorized(AuthenticationProvider authProvider);
}

다음으로 AuthenticationProcessor 를 확장하는 구체적인 프로세서를 만들어 보겠습니다 .

public class OAuthProcessor extends AuthenticationProcessor {

    public OAuthProcessor(AuthenticationProcessor nextProcessor) {
        super(nextProcessor);
    }

    @Override
    public boolean isAuthorized(AuthenticationProvider authProvider) {
        if (authProvider instanceof OAuthTokenProvider) {
            return true;
        } else if (nextProcessor != null) {
            return nextProcessor.isAuthorized(authProvider);
        }
        
        return false;
    }
}
public class UsernamePasswordProcessor extends AuthenticationProcessor {

    public UsernamePasswordProcessor(AuthenticationProcessor nextProcessor) {
        super(nextProcessor);
    }

    @Override
    public boolean isAuthorized(AuthenticationProvider authProvider) {
        if (authProvider instanceof UsernamePasswordProvider) {
            return true;
        } else if (nextProcessor != null) {
            return nextProcessor.isAuthorized(authProvider);
        }
    return false;
    }
}

여기에서 들어오는 권한 부여 요청에 대해 UsernamePasswordProcessorOAuthProcessor라는 두 개의 구체적인 프로세서를 만들었습니다 .

각각에 대해 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 는 인증 Provider가 UsernamePasswordProvider 의 인스턴스인지 확인합니다 .

예상 입력이 아닌 UsernamePasswordProcessor 는 OAuthProcessor 에 Delegation합니다 .

마지막으로 OAuthProcessor 가 명령을 처리합니다. 첫 번째 테스트에서 일치 항목이 있고 테스트에 통과합니다. 두 번째는 체인에 더 이상 프로세서가 없기 때문에 테스트가 실패합니다.

4. 시행 원칙

책임 사슬을 구현하는 동안 몇 가지 중요한 원칙을 염두에 두어야 합니다.

  • 체인의 각 프로세서에는 명령 처리를 위한 구현이 있습니다.
    • 위의 예에서 모든 프로세서에는 isAuthorized 구현이 있습니다.
  • 체인의 모든 프로세서는 다음 프로세서에 대한 참조를 가져야 합니다.
    • 위에서 UsernamePasswordProcessor 는 OAuthProcessor 에 Delegation합니다 .
  • 각 프로세서는 다음 프로세서에 Delegation할 책임이 있으므로 누락된 명령에 주의하십시오.
    • 다시 이 예에서 명령이 SamlProvider 의 인스턴스인 경우 요청이 처리되지 않고 승인되지 않을 수 있습니다.
  • 프로세서는 재귀 주기를 형성하면 안 됩니다.
    • 이 예제에서는 체인에 주기가 없습니다: UsernamePasswordProcessor -> OAuthProcessor . 그러나 UsernamePasswordProcessor를 OAuthProcessor의 다음 프로세서로 명시적으로 설정하면 UsernamePasswordProcessor - > OAuthProcessor -> UsernamePasswordProcessor라는 체인의 주기로 끝납니다 . 생성자에서 다음 프로세서를 사용하면 도움이 될 수 있습니다.
  • 체인에서 단 하나의 프로세서만이 주어진 명령을 처리합니다.
    • 이 예에서 들어오는 명령에 OAuthTokenProvider 인스턴스가 포함되어 있으면 OAuthProcessor명령을 처리합니다.

5. 실제 사용

Java 세계에서 우리는 매일 책임 사슬의 이점을 누리고 있습니다. 이러한 고전적인 예 중 하나는 여러 필터가 HTTP 요청을 처리할 수 있도록 하는 Java 의 서블릿 필터입니다. 이 경우 각 필터는 다음 필터 대신 체인을 호출합니다.

서블릿 필터에서 이 패턴을 더 잘 이해하기 위해 아래 코드 스니펫을 살펴보겠습니다 .

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);
    }
}

위의 코드 조각에서 볼 수 있듯이 체인의 다음 프로세서에 요청을 전달하려면 FilterChaindoFilter 메서드를 호출해야 합니다.

6. 단점

이제 책임 사슬이 얼마나 흥미로운지 살펴보았으므로 몇 가지 단점을 염두에 두어야 합니다.

  • 대부분 쉽게 깨질 수 있습니다.
    • 프로세서가 다음 프로세서를 호출하지 못하면 명령이 삭제됩니다.
    • 프로세서가 잘못된 프로세서를 호출하면 사이클이 발생할 수 있습니다.
  • 성능에 영향을 줄 수 있는 깊은 스택 추적을 생성할 수 있습니다.
  • 프로세서 간에 중복 코드가 발생하여 유지 관리가 증가할 수 있습니다.

7. 결론

이 기사에서는 들어오는 인증 요청을 승인하는 체인의 도움으로 책임 체인과 그 장단점에 대해 이야기했습니다.

그리고 항상 그렇듯이 소스 코드는 GitHub 에서 찾을 수 있습니다 .

Generic footer banner