책임 연쇄 패턴

김재연·2025년 8월 17일
post-thumbnail

회사에서 선임분들이 자주 사용하던 디자인 패턴에 대해 글을 작성해보려한다.

setNext()를 통해 다음에 진행될 인증방식에 대해 결정해주고, 계속해서 다음 클래스의 메서드르 호출해주면서 이가 동작하게 된다.

이런 형식으로 상속구조가 이루어져있고,
ValidationChain 내부 코드는 다음과 같다.

  • ValidationChain
public abstract class ValidationChain {  
  
    protected ValidationChain next;  
  
    public void setNextValidator(ValidationChain next) {  
        this.next = next;  
    }  
  
    public abstract void validate(Object target);  
  
}

ValidationChain은 next를 저장하고 있고(동일한 클래스), 또한, validate 메서드를 오버라이딩하라고 하고 있다.

그러면 이를 어떻게 활용할 수 있을까?

  • ValidationExecutor
@Component  
@RequiredArgsConstructor  
public class ValidationExecutor {  
  
    private final LoginService loginService;  
  
    private ValidationChain chain;  
  
    public void execute(AuthorizationDTO target) {  
        buildChain();  
        chain.validate(target);  
    }  
  
    private void buildChain() {  
        ValidationChain usernamePasswordValidator = new UsernamePasswordValidator(loginService);  
        ValidationChain clientValidator = new ClientValidator(loginService);  
        ValidationChain scopeValidator = new ScopeValidator();  
        ValidationChain grantTypeValidator = new GrantTypeValidator();  
  
        usernamePasswordValidator.setNextValidator(clientValidator);  
        clientValidator.setNextValidator(scopeValidator);  
        scopeValidator.setNextValidator(grantTypeValidator);  
  
        chain = usernamePasswordValidator;  
    }  
  
}

해당 코드를 보면 알 수 있듯이, setNextValidtor로 책임을 연쇄적으로 부여하는 것을 볼 수 있다. 딱봐도, 현재 객체의 validate을 호출하면, 다음 객체의 validate을 호출하는 패턴으로 볼 수 있다.

  • TokenAccess
@Override  
public boolean authenticate(Object o) {  
    String token = (String) o;  
    String convertedMd5Key = TokenUtil.extractTokenKey(token); // Key를 뽑아내면  
    OauthAccessToken accessToken = accessTokenRepository.findByTokenId(convertedMd5Key);  
    if (accessToken == null) {  
        ServletUtil.setAttribute(ACCESS_STATUS.name(), INVALID_TOKEN);  
        return false;  
    }  
  
    try {  
        return !accessTokenService.isExpired(accessToken.getToken());  
    } catch (Exception e) {  
        return false;  
    }  
}

@Override  
public void validate(Object target) {  
    if (!authenticate(target)) { 
        throw new InvalidTokenException("Invalid token");  
    }  
  
    if (next != null) {  
        next.validate(target);  
    }  
}

TokenAccess 내부 코드를 보면 알 수 있겠지만, 일단, Md5 알고리즘 방식의 토큰에서 key를 뽑아내고, 그 다음에 accessTokenRepository에서 ID를 통해 Token을 찾아준다. 그리고, 만일 accessToken이 null이라면 HttpServlet에다가 ACCESS_STATUS와 INVALID_TOKEN 이라는 정보를 넣어준다. 또한, expired된 경우 false, 그렇지 않은 경우 true를 반환한다.

그 다음에, validate을 호출 했을 떄, 만일 next가 null이 아니라면, validate을 호출해준다.

즉, 정리하면 authenticate를 호출하여 인증을 진행, 그리고 next.validate를 통해 마치 Chain으로 이어놓은 듯한 Validator들을 실행시킨다.

profile
끊임없이 '성장'하는 개발자 김재연입니다.

0개의 댓글