# 책임 연쇄 (Chain-of-Responsibility)

# 책임 연쇄 패턴이란 무엇인가요?

image

TIP

요청을 보내는 쪽(sender)과 요청을 처리하는(receiver) 쪽을 분리하는 패턴

--> 핸들러 체인을 사용해서 요청을 처리한다.

클라이언트로부터의 요청을 처리할 수 있는 처리객체를 집합(Chain)으로 만들어 부여함으로 결합을 느슨하기 위해 만들어진 디자인 패턴입니다.

일반적으로 요청을 처리할 수 있는 객체를 찾을 때 까지 집합 안에서 요청을 전달합니다.

실제로 굉장히 많이 쓰이는 패턴 중 하나입니다.

# 어떤 상황에서 사용해야 할까요?

  • 요청의 발신자와 수신자를 분리하는 경우

  • 요청을 처리할 수 있는 객체가 여러개일 때 그 중 하나에 요청을 보내려는 경우

  • 코드에서 처리객체(handler)를 명시적으로 지정하고 싶지 않은 경우

TIP

즉, 책임 연쇄 패턴은 요청을 처리할 수 있는 객체가 여러 개이고 처리객체가 특정적이지 않을 경우 권장되는 패턴입니다.

# 책임 연쇄 패턴 적용하기

  • 사용자의 요청을 처리할 때, 인증과 로깅 과정이 함께 이루어져야 한다고 가정해보자.
@Getter
@Setter
@AllArgumentsConstrunctor
public class Request {
    private String body;
}
  • 요청 객체
public abstract class RequestHandler {
    private RequestHandler nextHandler;

    public RequestHandler(RequestHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handle(Request request) {
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}
  • 책임 연쇄를 위한 상위 클래스
public class PrintRequestHandler extends RequestHandler {
    public PrintRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handle(Request request) {
        System.out.println(request.getBody());
        super.handle(request);
    }
}
public class LoggingRequestHandler extends RequestHandler {
    public LoggingRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handle(Request request) {
        System.out.println("로깅");
        super.handle(request);
    }
}
public class AuthRequestHandler extends RequestHandler {
    public AuthRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handle(Request request) {
        System.out.println("인증");
        super.handle(request);
    }
}
public class Client {
    private RequestHandler requestHandler;

    public Client(RequestHandler requestHandler) {
        this.requestHandler = requestHandler;
    }

    public void doWork() {
        Request request = new Request("Hello World!");
        requestHandler.handle(request);
    }

    public static void main(String[] args) {
        RequestHandler chain = new AuthRequestHandler(new LoggingRequestHandler(new PrintRequestHandler(null)));
        Client client = new Client(chain);
        client.doWork();
    }
}
  • 실 사용측

# 책임 연쇄 패턴의 장점과 단점

장점

  • 클라이언트 코드를 변경하지 않고, 새로운 핸들러를 체인에 추가할 수 있고, 순서도 변경할 수 있다. (OCP)

  • 각 핸들러들은 본인의 역할만을 수행하게 된다. (SRP)

  • 체인을 구조적으로 다양하게 구성할 수 있다.

단점

  • 다양한 필터들을 거치다 보니 디버깅이 쉽지 않다.

# 책임 연쇄 패턴의 실 사용 예시는?

  1. 자바의 서블릿

사용자가 요청시 서블릿에 접근하기 전에 다양한 필터를 거치도록 할 수 있다.

  1. 스프링의 시큐리티

스프링 프로젝트에 SpringSecuriry 의존성을 추가하고 아래와 같이 Security필터에 대한 설정을 할 수 있다. 아래에서는 모든 요청에 대한 접근을 허용한다는 것이다.

# 참고 자료

  • https://always-intern.tistory.com/1
  • https://kingchan223.tistory.com/306