본문 바로가기

Coding Note

[Design pattern] Chain of Responsibliity

Chain of Responsibility Pattern : 뭔가 일이 일어났을때 그 일을 처리할 책임을 적당한 대상한테 넘겨준다. Exception을 throw하는것도 비슷한 원리인데, Chain of responsibility pattern은 예외 만이 아니라 사건에 대한 처리역할을 적당한 대상에게 가도록 해주는 기법이다. 더하여 발생한 이벤트를 체인에 속한 여러 처리자에 걸쳐 처리할 수 있다.


이 패턴은 하나의 클래스의 인스턴스들간의 체인이라기보다는 여러 클래스간에 걸쳐 이루어지는 일이기 때문에 구조가 다른 클래스에 대해서 낮은 결합도로 동일한 이벤트에 대한 핸들링을 가능하게 한다는 점에서 주목할 만 하다.

 

 

또한 상황에 따라 동적으로 핸들러를 추가하거나 제거할 수 있으며 이러한 변화가 전체구조에 아무런 영향을 주지 않는다는 점에서 객체지향적인 목적을 달성한다고 볼 수 있다.

 

보통은 사건이 일어날만한 일에 대해 처리 클래스를 여러개 정의해두고 한데 묶어둔 후 사건이 일어나면 맨 앞의 클래스에게 '이거 처리해줘' 하고 넘겨주는식으로 체인의 스타트를 끊는다.


이벤트 버블링과 터널링에 적절한 예인것같다.

버블링이나 터널링은 하나의 이벤트가 발생했을때 연관된 컴포넌트 체인을 따라 바깥쪽 컴포넌트부터 안쪽으로 들어가거나 안쪽부터 바깥 컴포넌트로 거쳐 나온다. 그러면서 체인의 컴포넌트가 그 이벤트에 대해 처리할 필요가 있다면 각 컴포넌트에 맞는 처리를 해주게된다.


/* Request,java */

public class Request {

private int id;


public Request(int id){

this.id = id;

}


public int getId(){ return id; }

}


/* Handler.java */

public abstract class Handler {

private Handler next;


public Handler(){

next = null;

}


public Handler setNext(Handler handler){

next = handler;

return next;

}


public final void handlerRequest(Request request){

if(resolveRequest(request)==false){

if(next != null){

next.handlerRequest(request);

}

}

}


public abstract boolean resolveRequest(Request request);

}


/* Component.java */
public abstract class Component extends Handler {
// properties..
}

/* Panel.java */
public class Panel extends Component {
@Override
public boolean resolveRequest(Request request) {
switch(request.getId()){
case 0:
//..
return true;
case 1:
//..
return true;
default:
return false;
}

//여기에선 command pattern이 적용될 수 있다.

}
}

/* Button.java */
public class Button extends Component {
@Override
public boolean resolveRequest(Request request) {
switch (request.getId()){
case 0:
return true;
case 3:
return true;
default:
return false;
}
}
}

/* main */
public static void main(String[] args){
Handler component = new Panel();
component.setNext(new Button());

component.handlerRequest(new Request(0));
}

리스트를 만들어 묶어둔 후 처리를해도 비슷한 작업을 할 수 있지만, 리스트를 사용하게되면 리스트를 관리할 클래스를 따로 둬야한다. Chain of responsibility pattern을 적용하면 리스트없이 클래스가 서로 엮일 수 있으니 어떻게보면 편하다고 할 수 있다. 하지만 이렇게되면 처리의 흐름이 클래스단위로 이리저리 뛰기때문에 이벤트의 처리 흐름을 파악하는게 상당히 힘들어진다. 또한 모든 핸들러가 리퀘스트에 대한 처리를 떠넘긴다면 리퀘스트가 처리되지 않은채로 소멸될 수 있다. 처리되지 못한 리퀘스트에 대한 처리를 따로 추가할 필요가 있다.


한줄요약 : 하나의 이벤트가 서로다른 구조의 핸들러를 통해서 다양하게 처리될 수 있다

'Coding Note' 카테고리의 다른 글

[Design pattern] Iterator  (0) 2013.02.04
[Design pattern] Command  (0) 2013.02.04
[Design pattern] Prototype  (1) 2013.02.01
[Design pattern] Builder  (0) 2013.01.31
[Design pattern] Singleton  (0) 2013.01.31