본문 바로가기
Design Pattern

13. 책임 연쇄 패턴 (chain - of - responsibility)

by 킹차니 2021. 12. 23.

 

책임 연쇄 패턴 ⛓

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

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

 

 

 


 

코드로 알아보기

사용자가 특정 핸들러를 사용할 때, 이 사용자가 핸들러를 사용할 수 있는 사용자인지 인증을 해야하는 비즈니스 로직이 있다고 가정해보자.

먼저 Client의 코드는 아래와 같다.

이를 실행하면 아래와 같다.

 

요청인 Request 객체와 핸들러인 RequestHandler 객체는 아래와 같다.

 

RequestHandler는 단순히 Request의 body를 출력해준다.

 

❗️문제점 ❗️

그런데 위의 RequestHandler에 보이듯이 하나의 핸들러가 두가지 역할을 담당하고 있다.(주석에 써있는 글을 코드라고 가정한다.)

 그것은 바로 1.인증 관련 로직 2.RequestHandler의 출력 로직이다.

SRP에 위배된다.

 

이전까지 학습한 패턴들을 떠올리면 아래와 같이 할 수 있을 것이다. 

먼저 인증을 하는 새로운 핸들러를 만드는데, 이는 RequestHandler를 extends하도록 한다. 아래와 같다.

그리고 위에서 보이듯이 자신은 handler메소드를 통해 인증 관련 로직을 하고난 뒤, super로 원래의 Handler로직을 RequestHandler에게 맡기는 것이다. 이렇게 구현하면 SRP도 지키면서 인증 관련 로직을 추가할 수 있다.

 

아래의 RequestHandler를 보면 인증관련 로직은 사라지고, 자신의 역할만을 하고 있는 것을 볼 수 있다.

 

좋은 방법같지만 문제점이 여전히 발생한다.

❗️문제점❗️

문제점1. Client는 RequestHandler가 아닌 AuthRequestHandler를 사용해야 한다. (즉 Client가 사용해야하는 핸들러를 직접 알아야 함)

 

문제점2. 만약 사용자의 Request를 logging하는 새로운 로직이 삽입되어야한다면?? LogginRequestHandler를 만들어 Client가 사용하도록 해야하고, AuthRequestHandler는 또 어떻게 적용할 것인가??

 

이제 여기에 책임 연쇄 패턴을 적용하여 클라이언트는 구체적으로 어떤 핸들러를 사용해야하는지 몰라도 기존의 핸들러들이 수행되도록 수정해보자.

 

먼저 클래스 다이어그램에서 본 Handler 추상타입 클래스를 만들어야한다, 우리는 abstract 클래스로 만들어서 해당 클래스가 nextFilter를 참조 하도록 만들 것이다.

RequestHandler는 아래와 같다.

RequestHandler의 handle 메소드를 보면 nextHandler가 있다면 nextHandler의 handle을 실행하도록 구햔되어 있다.

이제 각 핸들러들은 위의 RequestHandler를 상속받아서 자신들의 로직을 구현하면 된다.

 

AuthRequestHandler

 

LoggingRequestHandler

 

PrintRequestHandler

 

 

이제 이를 사용해보자. 처음에는 인증이 완료된 요청으로 테스트 해본다.

위의 코드에서 보이듯이 외부에서 chain을 조립해주고, Client는 어떤 Handler를 사용하는지 몰라도 된다.

 

실행결과:

순서대로 chain의 로직이 수행된 것을 볼 수 있다.

 

이제는 인증이 완료되지 않은 요청으로 테스틀해보자.

 

실행결과:

 


 

장점과 단점

 

장점

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

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

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

 

단점

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

 

 


실제로 어디에서 사용되나?

 

1. 자바의 서블릿

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

만약 위와 같은 컨트롤러가 있고, "/hello"로 요청을 받으면 아래의 필터를 타도록한다.

 

 

2. 스프링의 시큐리티

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

 

 

출처: 인프런 백기선님 '코딩으로 학습하는 GoF 강의'
https://www.inflearn.com/course/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4