본문 바로가기

Design Pattern

[Java-Pattern] Chain of Responsibility

 

책임 떠넘기기 패턴

어떤 처리 요구가 들어왔을때, 그것을 처리 할 수 있는 인스턴스가 나타날때까지

그 처리를 넘기는 패턴이다.


예제프로그램은 임의의 숫자를 가진 트러블을 발생시키고, 트러블을 해결하는 클래스들을 종류별로

만들어 놓은 후 Chain of Responsibility패턴을 구현한 것이다.


1.Trouble - 발생한 트러블을 나타내는 클래스. 트러블 번호를 갖는다.

2.Support - 트러블을 해결하는 추상 클래스

3.NoSupport - 트러블을 해결하는 클래스 (항상 처리하지 않음.)

4.LimitSupport - 트러블을 해결하는 클래스

....


Trouble Class

public class Trouble {
    private int number;             // 트러블 번호
    public Trouble(int number) {    // 트러블의 생성
        this.number = number;
    }
    public int getNumber() {        // 트러블 번호를 얻는다.
        return number;
    }
    public String toString() {      // 트러블의 문자열 표현
        return "[Trouble " + number + "]";
    }
}

트러블을 나타내면 트러블 번호를 갖는다. 나중에 처리하는 클래스들은 이 번호를 가지고 자신이

처리 할 수 있는지의 여부를 결정한다.


Support Class

public abstract class Support {
    private String name;                    // 트러블 해결자의 이름
    private Support next;                   // 떠넘기는 곳
    public Support(String name) {           // 트러블 해결자의 생성
        this.name = name;
    }
    public Support setNext(Support next) {  // 떠넘길 곳을 설정
        this.next = next;
        return next;
    }
    public final void support(Trouble trouble) {  // 트러블 해결 순서
        if (resolve(trouble)) {
            done(trouble);
        } else if (next != null) {
            next.support(trouble);
        } else {
            fail(trouble);
        }
    }
    public String toString() {              // 문자열 표현
        return "[" + name + "]";
    }
    protected abstract boolean resolve(Trouble trouble); // 해결용 메소드
    protected void done(Trouble trouble) {  // 해결
        System.out.println(trouble + " is resolved by " + this + ".");
    }
    protected void fail(Trouble trouble) {  // 미해결
        System.out.println(trouble + " cannot be resolved.");
    }
}

next필드는 Support형으로 다음 문제를 해결할 클래스의 인스턴스를 가지고 있으며, 이는 setNext

메소드를 통해 설정 할 수 있다. resolve메소드는 하위 클래스에서 구현할 것을 상정한 추상 메소드입니다. 반환값이 true이면 해결한거고 아니면 해결 못 한 것..


NoSupport Class

public class NoSupport extends Support {
    public NoSupport(String name) {
        super(name);
    }
    protected boolean resolve(Trouble trouble) {     // 해결용 메소드
        return false; // 자신은 아무 처리도 하지 않는다.
    }
}

LimitSupprot Class

public class LimitSupport extends Support {
    private int limit;                              // 이 번호 미만이면 해결 할수 있다.
    public LimitSupport(String name, int limit) {   // 생성자
        super(name);
        this.limit = limit;
    }
    protected boolean resolve(Trouble trouble) {         // 해결용 메소드
        if (trouble.getNumber() < limit) {
            return true;
        } else {
            return false;
        }
    }
}


Support클래스를 상속하고 있는 실제 처리 클래스들은 다 이런식으로 구성되어있다.


Main..

public class Main {
    public static void main(String[] args) {
        Support alice   = new NoSupport("Alice");
        Support bob     = new LimitSupport("Bob", 100);
        Support charlie = new SpecialSupport("Charlie", 429);
        Support diana   = new LimitSupport("Diana", 200);
        Support elmo    = new OddSupport("Elmo");
        Support fred    = new LimitSupport("Fred", 300);
        // 연쇄의 형성
        alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
        // 다양한 트러블 발생
        for (int i = 0; i < 500; i += 33) {
            alice.support(new Trouble(i));
        }
    }
}

해결 인스턴스별로 각각 6개를 생성하고 연쇄를 형성한다. 이것은

alice인스턴스의 next필드에는 bob이

bob인스턴스의 next필드에는 charlie가..

이런식으로 들어가 있게 되는 것이고, 이것은 Support클래스에서


public final void support(Trouble trouble) {  // 트러블 해결 순서
        if (resolve(trouble)) {
            done(trouble);
        } else if (next != null) {
            next.support(trouble);
        } else {
            fail(trouble);
        }
여기서 사용된다. 예를 들어 Main클래스에서

alice.support(new Trouble(i));

로 최초 호출을 하고 있는데, 이는 alice의 resolve가 호출되고 alice는 무조건 false를 return하므로 , else문에 의해서 next.support(trouble)이 실행된다.

alice의 next는 bob이므로 bob.support와 같은 의미이고 이는 bob의 resolve를 호출하게 되는

이런 방식이다. (재귀적 호출)


즉, handler 클래스를 두고 이 클래스가 자기 자신을 호출하여 자기 필드에 있는 실제 처리 인스턴스들을 사용해 처리를 넘기는 것이다.


이패턴이 사용되지 않으면 요구를 하는 사람이 누가 처리할지 까지 알고 있어야 한다.