Table of Contents

[GoF 디자인 패턴] 책임 연쇄 (Chain of Responsibility) 패턴

책임 연쇄 (Chain of Responsibility) 패턴


행동(behavioral) 패턴 중 하나로, 여러 개의 객체 중에서 요청을 처리할 수 있는 객체를 찾아서 처리하도록 하는 패턴이다.

요청을 처리하는 객체(핸들러)들이 연결된 체인을 이루고 있으며, 요청을 처리할 수 있는 핸들러를 찾을 때까지 체인 상의 모든 핸들러가 요청을 받아서 처리할 수 있는지를 순차적으로 검사한다.

책임 연쇄 패턴 구성요소

  • Handler: 요청을 처리하는 메서드를 가진 인터페이스나 추상 클래스.
  • ConcreteHandler: 실제로 요청을 처리하는 구현 클래스.
  • Client: 요청을 보내는 객체

구현 예제

요청을 처리하는 메서드를 선언하는 Handler 인터페이스를 선언한다.

 1public abstract class Manager {
 2    protected String name;
 3    protected Manager superior;
 4
 5    public Manager(String name) {
 6        this.name = name;
 7    }
 8
 9    public void setSuperior(Manager superior) {
10        this.superior = superior;
11    }
12
13    public abstract void requestApplications(Request request);
14}

각각의 Manager 객체는 superior 변수를 통해 자신의 상사 매니저 객체를 참조하도록 되어 있다. Manager 객체는 스스로 해당 요청을 처리할 수 있는지를 판단하고, 처리할 수 없다면 상사 매니저(superior) 객체에게 해당 요청을 전달한다.
“요청을 처리하는 객체들 간의 연결고리 역할을 수행한다.”


실제로 요청을 처리하는 구현 클래스인 ConcreteHandler 클래스를 만든다.

 1public class GeneralManager extends Manager {
 2
 3    public GeneralManager(String name) {
 4        super(name);
 5    }
 6
 7    @Override
 8    public void requestApplications(Request request) {
 9        if (
10            request.getRequestType() == RequestType.PURCHASE &&
11            request.getAmount() < 10
12        ) {
13            System.out.println("GeneralManager 가 처리중입니다 : ");
14        } else {
15            superior.requestApplications(request);
16        }
17    }
18}
19
20public class MiddleManager extends Manager {
21
22    public MiddleManager(String name) {
23        super(name);
24    }
25
26    @Override
27    public void requestApplications(Request request) {
28        if (request.getRequestType() == RequestType.PURCHASE) {
29            System.out.println("MiddleManager 가 처리중입니다 : ");
30        } else {
31            superior.requestApplications(request);
32        }
33    }
34}
35
36public class SuperManager extends Manager {
37
38    public SuperManager(String name) {
39        super(name);
40    }
41
42    @Override
43    public void requestApplications(Request request) {
44        System.out.println("SuperManager 가 처리중입니다 : ");
45    }
46}

각각의 매니저 객체가 requestApplications 메서드를 사용하여 자신이 처리할 수 있는 요청을 처리하고 처리할 수 없을 경우 superior.requestApplications(request); 와 같이 상사 매니저 객체에게 요청을 전달한다.
“객체 간의 결합도를 낮출 수 있고, 코드의 유연성과 확장성을 높일 수 있다.”


책임 연쇄 패턴을 사용하는 Client 코드이다.

 1Manager manager = new GeneralManager("일반관리자");
 2Manager middleManager = new MiddleManager("중간관리자");
 3Manager superManager = new SuperManager("슈퍼관리자");
 4
 5// 다음으로 request 를 넘길 manager 설정
 6manager.setSuperior(middleManager);
 7middleManager.setSuperior(superManager);
 8
 9Request purchase = new Request(RequestType.PURCHASE, 1000);
10Request cancel = new Request(RequestType.CANCEL, 10);
11manager.requestApplications(purchase);
12manager.requestApplications(cancel);

setSuperior() 메서드를 사용하여 다음 Manager에게 요청을 전달할 수 있도록 연결고리를 설정한다. GeneralManager 객체의 requestApplications 메소드가 호출되면서 요청을 처리하지 못하면 자신의 상사 매니저에게 요청을 전달한다.
“객체 간의 연결고리 설정을 통해 코드의 유연성과 확장성이 높아지며, 객체 간의 결합도를 낮출 수 있다.”

책임 연쇄 패턴 고려사항

객체 간의 결합도를 낮춰야 하거나 요청을 처리할 객체를 동적으로 결정할 때 책임 연쇄 패턴을 사용하면 좋다. 다만 모든 요청을 처리해야 하는 경우나 책임 연쇄가 너무 길어진다면 책임 연쇄 패턴을 사용해서는 안된다.


책임 연쇄 패턴 사용 시 장점

  1. 객체 간의 결합도를 낮출 수 있다.
  2. 객체 간의 연결고리를 동적으로 설정하기 때문에 요청 처리를 유연하게 할 수 있다.

책임 연쇄 패턴 사용 시 단점

  1. 처리할 수 있는 객체가 없는 경우 요청이 처리되지 않을 수 있다. - 요청 처리 보장 X
  2. 요청을 처리할 객체를 찾기 위해 여러 객체를 검색하는 과정에서 오버헤드가 발생할 수 있다.