Updated:

1. 개요

메시지를 보내는 객체와 이를 받아 처리하는 객체들 간의 결합도를 없애기 위한 패턴

책임 연쇄 패턴(Chain Of Responsibility Pattern)은 행동 패턴(Behavioral Pattern)의 한 종류로, 메시지 송신측과 수신측을 분리하여 요청을 처리하는 기회를 다른 객체에 분산한다. 요청이 들어오면 해당 요청을 처리할 수 있는 객체를 찾을 때까지 연결 고리를 따라 요청을 전달하고, 적합한 객체를 발견하면 요청한 서비스를 제공한다.

2. 행동 패턴(Behavioral Pattern)

2-1. 행동 패턴이란?

행동 패턴이란 처리의 책임을 어떤 객체에게 할당하는 것이 좋은지, 알고리즘을 어떤 객체에 정의하는 것이 좋은지 등의 책임 분배와 관련된 패턴이다.

2-2. 행동 패턴 종류

3. 구성

[출처 : GoF의 디자인 패턴]

  • Handler : 요청을 처리하는 인터페이스를 정의하고, 다음 객체에게 메시지 전송

  • ConcreteHandler : 해당 요청을 처리할 수 있는 경우 직접 처리

  • Client : ConcreteHandler 객체에게 필요한 요청 전송

4. 예제 코드

열이 났을 때, 체온별로 다르게 조치를 취해야 한다고 가정해보자. 37도 이하인 경우 휴식을 취하고, 38도 이하인 경우 약을 먹고, 40도 이하인 경우 병원을 방문해야 한다고 할 때, Chain Of Responsibility Pattern을 이용하면 본인의 책임이 아닌 경우 다른 객체로 책임을 위임하여 체온별로 책임을 적절하게 분배할 수 있다.

4-1. Handler

[Fever.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class Fever {

    protected int limitTemperature;
    protected Fever next;

    public void setNext(Fever fever) {
        next = fever;
    }

    public void action(int temperature) {
        if (temperature <= limitTemperature) {
            writeMessage(temperature);
        } else {
            if(next != null) {
                next.action(temperature);
            }
        }
    }

    abstract protected void writeMessage(int temperature);
}

Line 11 : 현재 체온이 제한 체온보다 낮은 경우(직접 처리가 가능한 경우)

Line 14 ~ 16 : 위임할 객체가 존재하는 경우 책임 위임

4-2. ConcreteHandler

[Rest.java]

1
2
3
4
5
6
7
8
9
10
public class Rest extends Fever{

    public Rest(int limitTemperature) {
        this.limitTemperature = limitTemperature;
    }

    protected void writeMessage(int temperature) {
        System.out.println("Temperature : " + temperature + " -> Rest!");
    }
}

[Medicine.java]

1
2
3
4
5
6
7
8
9
10
public class Medicine extends Fever{

    public Medicine(int limitTemperature) {
        this.limitTemperature = limitTemperature;
    }

    protected void writeMessage(int temperature) {
        System.out.println("Temperature : " + temperature + " -> Medicine!");
    }
}

[Hospital.java]

1
2
3
4
5
6
7
8
9
10
public class Hospital extends Fever{

    public Hospital(int limitTemperature) {
        this.limitTemperature = limitTemperature;
    }

    protected void writeMessage(int temperature) {
        System.out.println("Temperature : " + temperature + " -> Hospital!");
    }
}

5. 테스트

[Clinet.java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Client {

    public static void main(String[] args) {
        Fever fever1 = new Rest(37);
        Fever fever2 = new Medicine(38);
        Fever fever3 = new Hospital(40);
        fever1.setNext(fever2);
        fever2.setNext(fever3);

        fever1.action(37);
        fever1.action(38);
        fever1.action(39);
    }
}

[실행 결과]

6. 특징

  • 낮은 결합도 : 메시지 송신측과 수신측 모두 서로를 알 필요가 없음

  • 높은 유연성 : 책임의 분산이 가능하므로 런타임 시점에 책임 변경 및 확장 가능

  • 낮은 신뢰성 : 객체간 연결이 제대로 정의되지 않은 경우 요청이 처리되지 않을 수 있음

Updated:

Leave a comment