# 책임 연쇄 (Chain-of-Responsibility)
# 책임 연쇄 패턴이란 무엇인가요?
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)
체인을 구조적으로 다양하게 구성할 수 있다.
단점
- 다양한 필터들을 거치다 보니 디버깅이 쉽지 않다.
# 책임 연쇄 패턴의 실 사용 예시는?
- 자바의 서블릿
사용자가 요청시 서블릿에 접근하기 전에 다양한 필터를 거치도록 할 수 있다.
- 스프링의 시큐리티
스프링 프로젝트에 SpringSecuriry 의존성을 추가하고 아래와 같이 Security필터에 대한 설정을 할 수 있다. 아래에서는 모든 요청에 대한 접근을 허용한다는 것이다.
# 참고 자료
- https://always-intern.tistory.com/1
- https://kingchan223.tistory.com/306