[DesignPattern] Chain of responsibility pattern

2014. 1. 20. 09:24Architecture/DesignPattern

반응형

Chain of responsibility Pattern


 개요

 예제(Java)

 같이보기

 참고 사항


<< 개요 >>

Chain of responsibility Pattern 이란?

                                                           (참고 사이트 : 위키피디아 - http://ko.wikipedia.org/wiki/Chain_of_responsibility_%ED%8C%A8%ED%84%B4)

객체 지향 디자인에서 chain-of-responsibility pattern은 명령 오브젝트와 일련의 프로세스 오브젝트를 포함하는 디자인 패턴이다. 각각의 프로세스 오브젝트는 명령 오브젝트를 핸들할 수 있는 연산의 집합으로 이루어지고, 체인안의 프로세스 오브젝트가 핸들할 수 없는 행해진다. 이 작동방식은 새로운 프로세스 오브젝트에서 체인의 끝까지에도 포함된다.

표준 chain-of-responsibility model이 변화하면서, 몇몇 핸들러들은 다양한 방향으로 명령을 보내 책임을 트리 형태로 바꾸는 관제사 역할을 하기도 한다. 몇몇 경우에서는, 프로세스 오브젝트가 상위의 프로세스 오브젝트와 명령을 호출하여 작은 파트의 문제를 해결하기 위해 재귀적으로 실행된다. 이 경우 재귀는 명령이 처리되거나 모든 트리가 탐색될때까지 진행되게 된다. XML(파싱되었으나 실행되지 않은)인터프리터가 알맞은 예가 된다.

이 패턴은 결합을 느슨하게 하기 위해 고안되었으며 가장 좋은 프로그래밍 사례로 꼽힌다.

라고는 되어있는데 무슨 내용인지...처음에는 전혀 Feel을 느낄 수 가 없었다..:D


우선은 아래의 예제를 보고 어떤 녀석인지 감을 잡아보도록 하자.

아! 예제를 보기전에 클래스 다이어그램을 보도록 하자.


<< 예제(Java) >>

예제는 사칙연산에 대해서 구현을 해보겠다. 참고사항의 동영상에 나오는 소스이다.

이해 돕기에 좋은 소스 인 것 같아서 선택하였다! ㅋㅋ


위의 클래스 다이어그램 처럼 우선 Interface인 Handler를 구현하여 보자. 명명은 Chain으로 하겠다.

1) Chain Interface : 2가지로 구성 되어질 수 있는데 하나는  객체를 엮을 수 있는(Chain) 

    setNextChain()이고, 또 다른 하나는 구현하여 사용하게 되는 calculate() 이다.

package kr.pe.acet.chainOfResposibility;

public interface Chain {

public void setNextChain(Chain nextChain);

public void calculate(Numbers req);

}


2) Chain의 구현부에서 사용 되어 질 Numbers.java를 만들어보자.

    내부 구조는 계산 되어질 숫자형 2개, 어떤 작업인지를 뜻하는 String 으로 변수가 구성되어져있다.

    그리고 생성자와 getter 들이 있다.

package kr.pe.acet.chainOfResposibility;

public class Numbers {


private int number1;

private int number2;

private String calculationWanted;

public Numbers(int number1, int number2, String calWanted){

this.number1 = number1;

this.number2 = number2;

this.calculationWanted = calWanted;

}


public int getNumber1() {

return number1;

}


public int getNumber2() {

return number2;

}


public String getCalculationWanted() {

return calculationWanted;

}

}



3) Chain Interface의 구현부들(

   - AddNumbers.java

package kr.pe.acet.chainOfResposibility;

public class AddNumbers implements Chain{

private Chain nextInChain;


@Override

public void setNextChain(Chain nextChain) {

this.nextInChain = nextChain;

}


@Override

public void calculate(Numbers req) {


if(req.getCalculationWanted() == "add"){

System.out.println(req.getNumber1()+" + "+req.getNumber2()+"="+(req.getNumber1()+req.getNumber2()));

}else{

            nextInChain.calculate(req);

}

}


}



   - SubtractNumbers.java

package kr.pe.acet.chainOfResposibility;

public class SubtractNumbers implements Chain{

private Chain nextInChain;


@Override

public void setNextChain(Chain nextChain) {

this.nextInChain = nextChain;

}


@Override

public void calculate(Numbers req) {


if(req.getCalculationWanted() == "sub"){

System.out.println(req.getNumber1()+" - "+req.getNumber2()+"="+(req.getNumber1()-req.getNumber2()));

}else{

            nextInChain.calculate(req);

}

}


}



   - MultiNumbers.java

package kr.pe.acet.chainOfResposibility;

public class MultiNumbers implements Chain{

private Chain nextInChain;


@Override

public void setNextChain(Chain nextChain) {

this.nextInChain = nextChain;

}


@Override

public void calculate(Numbers req) {


if(req.getCalculationWanted() == "multi"){

System.out.println(req.getNumber1()+" * "+req.getNumber2()+"="+(req.getNumber1()*req.getNumber2()));

}else{

            nextInChain.calculate(req);

}

}


}



   - DivideNumbers.java

package kr.pe.acet.chainOfResposibility;

public class DivideNumbers implements Chain{

private Chain nextInChain;


@Override

public void setNextChain(Chain nextChain) {

this.nextInChain = nextChain;

}


@Override

public void calculate(Numbers req) {


if(req.getCalculationWanted() == "div"){

System.out.println(req.getNumber1()+" / "+req.getNumber2()+"="+(req.getNumber1()/req.getNumber2()));

}else{

            System.out.println("Only works for add, sub, mult, div~!!");

}

}


}



4) Test Code

package kr.pe.acet.chainOfResposibility;

import static org.junit.Assert.*;


import org.junit.Test;


public class ChainOfResponsibilityTestCode {


@Test

public void chainOfResponsibilityTest() {

Chain chainCal1 = new AddNumbers();

Chain chainCal2 = new SubtractNumbers();

Chain chainCal3 = new MultiNumbers();

Chain chainCal4 = new DivideNumbers();

chainCal1.setNextChain(chainCal2);

chainCal2.setNextChain(chainCal3);

chainCal3.setNextChain(chainCal4);

              //Numbers request = new Numbers(10, 29, "add");

             //Numbers request = new Numbers(10, 29, "multi");

Numbers request = new Numbers(10, 29, "acet");

chainCal1.calculate(request);

}


}



5) 결과

Numbers request = new Numbers(10, 29, "add");   일 경우

     : 10 + 29=39     

   

Numbers request = new Numbers(10, 29, "multi"); 일 경우

10 * 29=290


Numbers request = new Numbers(10, 29, "acet"); 일 경우는???

이 답을 대답 할 수 있다면 Chain of responsibility pattern을 이해가 된 것이라고 생각이 든다!

[ Only works for add, sub, mult, div~!! ] => 답은 드래그~~~:D



<< 같이 보기 >>

인터프리터 패턴과 비슷한 느낌을 받았다.


study : 


굿택님 - 패턴정의 소개, 클래스 다이어그램 소개, 클라이언트에서 핸들러에게 책임을 주면 줄을 서있고 차레차레 일을 전달

Handler : Request를 처리 하기 위한 인터페이스를 정의, 다음 것의 링크를 정의

이 패턴의 목적은 객체간의 의존성을 약화시킨다.

예제 시연..


라낑님 : 위키피디아 개념 설명, 로그 관련 예제 시연, 스프링 시큐리티- 서블릿필터 예제 


<< 참고 사항 >>

동영상 사이트 :  http://www.youtube.com/watch?v=jDX6x8qmjbA


동영상에 외국인 아저씨가 코딩 한대로 했는데...틀린 부분이 있었다!!!!

if(req.getCalculationWanted() == "add"){

if(req.getCalculationWanted() == "div"){

요런 녀석들은...equals를 사용하는게 맞다^-^;

if(req.getCalculationWanted().equals("add")){

if(req.getCalculationWanted().equals("div")){



               - END -





반응형

'Architecture > DesignPattern' 카테고리의 다른 글

[DesignPattern] Decorator Pattern  (2) 2014.01.27
[DesignPattern] Visitor pattern  (0) 2014.01.11
[DesignPattern] Iterator pattern  (0) 2014.01.06
[DesignPattern] flyweight pattern  (0) 2014.01.06
[DesignPattern] state pattern  (0) 2013.12.31