[Design Patterns] Chain of Responsibility
목차
개요
내용
요약
요청을 처리할 수 있는 기회를 여러 객체에게 줌으로써 요청을 받은 객체와 처리하는 객체를 분리하자.
예시
GUI 프로그램을 생각해봅시다. 이 프로그램에서 사용자는 버튼 등의 컴포넌트를 클릭하면 도움말을 볼 수 있습니다. 프로그램은 도움말을 어떻게 보여줘야 할까요? 예를 들어 사용자가 버튼을 클릭했다면, 프로그램은 먼저 해당 버튼에 맞는 도움말이 있는지 확인하고 없다면 버튼을 가지고 있는 컨테이너에 도움말이 있는지 확인하는 작업을 연속적으로 취해 도움말이 있다면 도움말을 표시하고 도움말이 없다면 프로그램 최상위에 있는 도움말을 보여줘야 할 것입니다.
이 때 사용할 수 있는 패턴이 책임 연쇄 패턴입니다. 책임 연쇄 패턴은 객체들을 체인으로 묶어 요청이 오면 체인을 따라 진행하면서 요청을 처리할 수 있는 객체가 처리하는 방식의 패턴입니다. 만약 사용자가 버튼을 클릭하고 버튼, 대화창에 도움말이 없다면 아래와 같은 흐름으로 시스템이 동작할 것입니다.
만약 도움말이 있다면 아래와 같이 동작할 것입니다. 대화창 객체가 요청을 처리할 수 있기 때문에 애플리케이션 객체까지 가지 않는 모습입니다.
구조
이야깃거리
언제 써야 할까?
- 하나 이상의 객체가 요청을 처리할 수도 있고 각 객체는 이전에 어떤게 호출되었는지 알지 못해도 될 때
- 요청을 처리하는 객체들이 동적으로 지정될 수 있어야할 때
장단점
- (Pros) 커플링 감소. 요청을 받는 객체는 요청을 처리하는 객체를 알지 못합니다. 반대도 마찬가지입니다. 책임 연쇄 패턴을 사용하면 이 두 객체 사이에 디커플링이 됩니다.
- (Pros) 요청을 처리하는 핸들러를 동적으로 설정할 수 있음.
- (Cons) 요청이 처리되지 않을 수 있음. 핸들러가 동적으로 설정될 수 있음에 따라 시스템은 해당 요청이 꼭 처리된다는 보장을 해줄 수 없습니다. 즉, 체인의 끝까지 가도 요청이 처리되지 못할 수 있습니다.
Case Study
Case 1. Java Servlet Filter Chain
자바의 Servlet은 사용자 요청을 받아서 응답해주는 클래스입니다. 사용자 요청이 오면 ServletRequest, ServletRespnose 객체가 생성됩니다. 개발자는 프로그램에서 jakarta.servlet.Filter 인터페이스를 구현함으로써 해당 필터에서 서블릿을 처리할지 다른 필터로 넘길지 결정할 수 있습니다.
모든 필터는 Filter인터페이스를 구현해야 합니다.
이 인터페이스에서 doFilter의 인자로 chain이 있는 것을 볼 수 있습니다. 만약 해당 필터가 요청을 응답할 수 있으면 response를 조작해 응답을 설정한 후 그냥 return을 하면 되고, 그게 아니면 chain.doFilter(..)를 호출해 다음 핸들러로 요청을 넘기면 됩니다.
출처
GoF Design Patterns