CS/디자인패턴

[디자인패턴] ChainOfResposibility 패턴 (책임 연쇄 패턴, 책임 넘기기 패턴)

mabb 2023. 6. 21. 14:42
반응형

▶디자인 패턴 ( Design Pattern)

:프로그램 개발 시 문제 해결을 위하여 빈번히 사용되는 개발자들의 경험, 내적인 축적에 대하여,
GoF(Gang of Four) 라 불리는 4인의 개발자들이 각각을 패턴으로 정의하고 이름을 붙였다.
이를 디자인 패턴 (Design Pattern)이라고 한다.
 23개의 디자인 패턴을
『Elements of Reusable Object-Oriented Software』
라는 책으로 발간하였다.

Gang of Four 분들은 모두 안경을 썼다.

 

▷디자인 패턴의 용어를 빌리면 서로의 아이디어를 보다 용이하게 비교, 논의할 수 있게 된다.
▷재사용과 기능확장이 쉬운 소프트웨어를 만들기 위한 유익한 기법이 바로 디자인 패턴이다.

 

---------------------------------------------------------
1. Iterator
2. Adapter
3. Template Method
4. Factory Method
5. Singleton
6. Prototype
7. Builder
8. Abstract Factory
9. Bridge
10. Strategy
11. Composite
12. Decorator
13. Visitor
14. Chain of Responsibility
15. Facade
16. Mediator
17. Observer
18. Memento
19. State
20. Flyweight
21. Proxy
22. Command
23. Interpreter
---------------------------------------------------------

▶ChainOfResposibility  패턴

"할 수 없으면 뒷사람에게 책임 떠넘기기"
"책임자 체인 (핸들러 체인)"
"클라이언트는 맨 앞의 책임자에게 요청"
"클라이언트가 누구에게 일을 맡길지 일일이 알 필요 없음"


-왜 사용하는가
-클래스다이어그램
-각 클래스(인터페이스)의 역할
-Java소스

▶ChainOfResposibility 패턴에 대한 이해

-책임자를 줄지어 놓고, 앞의 책임자부터 할 수 있으면 처리하고 못하면 뒤로 넘기는 패턴이다.

-클라이언트는 최초의 책임자에게만 요청한다. 요청 사항은 처리할 수 있는 책임자가 처리한다.

-끝까지 뒤로 넘겨도 처리할 수 있는 책임자가 없으면 예외처리 등을 한다.

-요청 시 어떤 책임자에게 맡길지까지 클라이언트가 결정하는 것은 '어떤 업무를 어떤 책임자에게 맡길지'
책임자의 업무까지 클라이언트가 알고 있어야 함을 의미한다.

-동적으로 chan의 형태를 바꿀 수 있다.

-여기서 책임자를 핸들러(Handler)라고 칭한다. 핸들러는 독립적으로 특정 요청사항을 처리하는 독립 객체
정도로 이해한다. 자바스크립트에서 이벤트 핸들러를 생각해 보면 특정 이벤트라는 요청 사항을 담당하여 처리하는 이벤트 핸들러가 있다. 이러한 핸들러를 일렬로 줄지어 체인을 만들고 앞에서부터 처리할 수 있으면 처리하고 할 수 없으면 뒤로 넘기는 것이다.

-이벤트 버블링, 이벤트 캡쳐링이 ChainOfResponsibility의 예인 것으로 보인다.

 

▶왜 사용하는가

클라이언트는 어떤 책임자에게 맡길지 몰라도,  책임 연쇄 사슬  맨 앞의 책임자에게만 요청하면 된다. 각각의 책임자들에게도 장점이 있는데 본인이 처리할 수 없으면 뒤로 떠넘기기만 하면 되기 때문에 본인의 처리 로직에 집중할 수 있다.
클라이언트가 적절한 책임자를 찾아서 요청하기 위해서 클라이언트는 어떤 책임자가 어떤 업무를 처리할 수 있는지에 대한 정보를 알고 있어야 한다. 또한 if문등으로 클라이언트 단에서 요청사항을 어떤 책임자에게 맡길지 정한다면 동적인 형태로 책임자를 변경하기 어렵다.

 

▶클래스다이어그램

ChainOfResponsibility 패턴의 클래스다이어그램

 

▶각 클래스(인터페이스)의 역할

▷클라이언트 역할 - Main.java

핸들러 체인의 맨 앞의 핸들러에게 요청 사항을 전달한다.

▷요청 사항 역할 - Trouble.java

여기서는 숫자를 가지고 있어서 각 핸들러가 해당 요청사항을 처리할 수 있는지 파악한다.

▷책임자(핸들러) 역할 - Support.java

핸들러 체인을 만들기 위한 next필드와 setNext() 메서드를 가지고 있으며 템플릿 메서드 패턴으로 책임 떠넘기기 로직 및 처리 완료, 처리 실패, 처리 로직 resolve() 등의 메서드를 정의한다.

▷구체적인 책임자(핸들러) 역할 - *Support.java

resolve()를 구체화하고 해당 요청사항을 처리할 수 있는지 여부를 반환한다.

 

 

▶Java 소스

*java1.8 이전 버전을 사용하는 교재를 참고하였습니다.
Java API 문서 등을 참조하여 제네릭을 적용하는 등 소스를 개선할 필요가 있습니다.
(https://docs.oracle.com/en/java/javase/20/docs/api/)

▷클라이언트 역할 - Main.java

package main.java.designpattern.chainofresponsibility;

public class Main {
    public static void main(String[] args){
        Support no = new NoSupport("NoMan");
        Support limit = new LimitSupport("limitMan100",100);
        Support special = new SpecialSupport("specialMan462", 462);
        Support limit2 = new LimitSupport("limitMan200", 200);
        Support odd = new OddSuport("oddMan");
        Support limit3 = new LimitSupport("limitMan300", 300);

        no.setNext(limit).setNext(special).setNext(limit2).setNext(odd).setNext(limit3);

        for(int i=0; i<500; i+=33){
            no.support(new Trouble(i));
        }
    }
}

 

▷요청 사항 역할 - Trouble.java

package main.java.designpattern.chainofresponsibility;

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.java

package main.java.designpattern.chainofresponsibility;

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);
        }
    }
    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");
    }
    @Override
    public String toString(){
        return "["+name+"]";
    }
}

 

▷구체적인 책임자(핸들러) 역할 - *Support.java

NoSupport.java

package main.java.designpattern.chainofresponsibility;

public class NoSupport extends Support{
    public NoSupport(String name) {
        super(name);
    }
    @Override
    protected boolean resolve(Trouble trouble) {
        return false;
    }
}

 

LimitSupport.java

package main.java.designpattern.chainofresponsibility;

public class LimitSupport extends Support{
    private int limit;

    public LimitSupport(String name, int limit) {
        super(name);
        this.limit = limit;
    }

    @Override
    protected boolean resolve(Trouble trouble) {
        if(trouble.getNumber() < limit){
            return true;
        }else{
            return false;
        }
    }
}

 

OddSuport.java

package main.java.designpattern.chainofresponsibility;

public class OddSuport extends Support {
    public OddSuport(String name) {
        super(name);
    }

    @Override
    protected boolean resolve(Trouble trouble) {
        if(trouble.getNumber() % 2 == 1){
            return true;
        }else{
            return false;
        }
    }
}

 

SpecialSupport.java

package main.java.designpattern.chainofresponsibility;

public class SpecialSupport extends Support{
    private int number;

    public SpecialSupport(String name,int number) {
        super(name);
        this.number = number;
    }
    @Override
    protected boolean resolve(Trouble trouble) {
        if(trouble.getNumber() == number){
            return true;
        }else{
            return false;
        }
    }
}

 

---------------------------------------------------------
※참고자료
-Java언어로 배우는 디자인 패턴 입문
-Headfirst Design Pattern
-나무위키, 위키백과, 네이버백과
-리팩토링구루(https://refactoring.guru/ko)

반응형