본문 바로가기

IT/디자인 패턴(Design Pattern)

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

1) 개요

클라이언트로부터의 요청을 처리할 수 있는 처리객체를 집합(Chain)으로 만들어 부여함으로 결합을 느슨하기 위해 만들어진 디자인 패턴입니다.

일반적으로 요청을 처리할 수 있는 객체를 찾을 때 까지 집합 안에서 요청을 전달합니다.

실제로 굉장히 많이 쓰이는 패턴 중 하나입니다.


1. 책임 연쇄 패턴이 적용되는 경우

- 요청의 발신자와 수신자를 분리하는 경우

- 요청을 처리할 수 있는 객체가 여러개일 때 그 중 하나에 요청을 보내려는 경우

- 코드에서 처리객체(handler)를 명시적으로 지정하고 싶지 않은 경우


즉, 책임 연쇄 패턴은 요청을 처리할 수 있는 객체가 여러 개이고 처리객체가 특정적이지 않을 경우 권장되는 패턴입니다.


2. 장점

- 결합도를 낮추며, 요청의 발신자와 수신자를 분리시킬 수 있습니다.

- 클라이언트는 처리객체의 집합 내부의 구조를 알 필요가 없습니다.

- 집합 내의 처리 순서를 변경하거나 처리객체를 추가 또는 삭제할 수 있어 유연성이 향상됩니다.

- 새로운 요청에 대한 처리객체 생성이 매우 편리해집니다.


3. 단점

- 충분한 디버깅을 거치지 않았을 경우 집합 내부에서 사이클이 발생할 수 있습니다.

- 디버깅 및 테스트가 쉽지 않습니다.


2) UML


- Handler : 요청을 수신하고 처리객체들의 집합에 전달하는 인터페이스입니다. 집합의 첫 번째 핸들러에 대한 정보만 가지고 있으며 그 이후의 핸들러에 대해서는 알지 못합니다.

- Concrete handlers : 요청을 처리하는 실제 처리객체입니다.

- Client : 요청을 전달하는 클라이언트입니다.


3) 예제


1
2
3
4
5
public interface Chain {
    public abstract void setNext(Chain nextInChain);
    public abstract void process(Number request);
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
public class Number {
    private int number;
    
    public Number(int number) {
        this.number = number;
    }
    public int getNumber() {
        return number;
    }
    
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class NegativeProcessor implements Chain{
    private Chain nextInChain;
    
    @Override
    public void setNext(Chain nextInChain) {
        this.nextInChain = nextInChain;
    }
 
    @Override
    public void process(Number request) {
        if(request.getNumber() < 0) {
            System.out.println("NegativeProcessor : " + request.getNumber());
        } else {
            nextInChain.process(request);
        }
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ZeroProcessor implements Chain{
    private Chain nextInChain;
    
    @Override
    public void setNext(Chain nextInChain) {
        this.nextInChain = nextInChain;
    }
 
    @Override
    public void process(Number request) {
        if(request.getNumber() == 0) {
            System.out.println("ZeroProcessor : " + request.getNumber());
        } else {
            nextInChain.process(request);
        }
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class PositiveProcessor implements Chain{
    private Chain nextInChain;
    
    @Override
    public void setNext(Chain nextInChain) {
        this.nextInChain = nextInChain;
    }
 
    @Override
    public void process(Number request) {
        if(request.getNumber() > 0) {
            System.out.println("PositiveProcessor : " + request.getNumber());
        } else {
            nextInChain.process(request);
        }
    }
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
    public static void main(String[] args) {
        Chain c1 = new NegativeProcessor();
        Chain c2 = new ZeroProcessor();
        Chain c3 = new PositiveProcessor();
        
        c1.setNext(c2);
        c2.setNext(c3);
        
        c1.process(new Number(90));
        c1.process(new Number(-50)); 
        c1.process(new Number(0)); 
        c1.process(new Number(91)); 
    }
}
cs