Motivation
다른 클래스에게 책임을 넘겨야하는 경우가 있다.
- beginner approach - 전부 퍼블릭으로 만들기
- expert approach - using the 책임 연쇄 패턴
책임연쇄패턴을 사용하면 어떤 객체가 수행할지는 모른체 명령을 날릴수 있다. 한 객체는 누가 실행할지는 모르지만 일단 요청을 전달한다.
요청을 전달받은 객체는
- 직접 처리하거나
- 다른 객체에게 넘기거나
- 둘다 할 수 있다.
자판기의 동전 구멍이 책임연쇄패턴의 예시이다. 동전별로 구멍이 있는것이 아니라 동전 구멍은 딱 하나만 있다. 동전의 적절한 위치는 명령의 수신자가 결정한다. (수신자 = 저울???)
Intent
- 요청을 하는 객체(Client)와 실제 요청을 처리하는 객체를 분리하여 클라이언트와 실질 처리 로직을 분리한다.
- 객체는 체인의 일부가 된다. 요청을 처리 될때까지 객체의 체인을 따라 전달된다.
Implementation

- 핸들러 - 요청을 처리하는 방식에 대한 인터페이스 제공
- 구체 핸들러 - 요청 처리 로직 제공
- 클라이언트 - 체인의 첫번째 핸들러에게 Command 날림
Code Example
package oodesign.design.behavioral.chainofresponsiblity; class Request { private int m_value; private String m_description; public Request(String description, int value) { m_description = description; m_value = value; } public int getValue() { return m_value; } public String getDescription() { return m_description; } } abstract class Handler { protected Handler m_successor; public void setSuccessor(Handler successor) { m_successor = successor; } public abstract void handleRequest(Request request); } class ConcreteHandlerOne extends Handler { public void handleRequest(Request request) { if (request.getValue() < 0) { //if request is eligible handle it System.out.println("\tConcreteHandlerOne.HandleRequest : " + request.getDescription() + request.getValue()); } else { super.m_successor.handleRequest(request); } } } class ConcreteHandlerThree extends Handler { public void handleRequest(Request request) { if (request.getValue() >= 0) { //if request is eligible handle it System.out.println("\tConcreteHandlerThree.HandleRequest : " + request.getDescription() + request.getValue()); } else { super.m_successor.handleRequest(request); } } } class ConcreteHandlerTwo extends Handler { public void handleRequest(Request request) { if (request.getValue() > 0) { //if request is eligible handle it System.out.println("\tConcreteHandlerTwo.HandleRequest : " + request.getDescription() + request.getValue()); } else { super.m_successor.handleRequest(request); } } } public class Main { public static void main(String[] args) { // Setup Chain of Responsibility Handler h1 = new ConcreteHandlerOne(); Handler h2 = new ConcreteHandlerTwo(); Handler h3 = new ConcreteHandlerThree(); h1.setSuccessor(h2); h2.setSuccessor(h3); // Send requests to the chain h1.handleRequest(new Request("Negative Value ", -1)); h1.handleRequest(new Request("Zero Value ", 0)); h1.handleRequest(new Request("Positive Value ", 1)); } }
ConcreteHandlerOne.HandleRequest : Negative Value -1 ConcreteHandlerThree.HandleRequest : Zero Value 0 ConcreteHandlerTwo.HandleRequest : Positive Value 1 Process finished with exit code 0
세개의 핸들러가 체인을 이루고 있다.
ConcreteHandlerOne
→ ConcreteHandlerTwo
→ ContreteHandlerThree
음수처리 → 양수 처리 → 0 처리
Applicablity
책임 연쇄 패턴을 적절하게 사용할 수 있는 경우
- 두개 이상의 객체가 명령을 처리할 수 있을때
- 핸들러가 이미 알려져 있지 않은 경우
- 핸들러가 자동으로 결정해야 하는경우
- 여러 객체를 처리할 방법을 동적으로 결정해야 하는 경우
Examples
- 너무 많다.
Specific problems & Implementation
- 핸들러가 처리할 수 있는 요청에 대한 인터페이스를 정의하자.
- 체인의 끝에 처리되지 않은 요청이 있는지 확인하자