Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 공부
- 람다
- JPA
- 후기
- Design Pattern
- 인강리뷰
- 에러
- Oracle
- 우아한테크코스
- javascript
- 이펙티브자바
- study
- 독서
- 독서리뷰
- 매핑
- 자바
- Singleton
- Head First Design Pattern
- 알고리즘
- spring
- math
- 카카오톡1차
- 프로그래머스
- Eclipse
- Java
- 오라클
- 인코딩
- 디자인패턴
- 인프런
- 회고
Archives
- Today
- Total
Lee's Grow up
[디자인패턴/Design Pattern] Chain of Responsibility 역할 사슬 패턴 본문
반응형
관련 내용은 [자바 언어로 배우는 디자인 패턴 입문]
,[Head First Design Pattern]
의 내용을 참고해서 정리한 글입니다.
잘못된 부분은 댓글로 피드백 부탁드립니다.
1. Chain of Responsibility 패턴이란?
요청이 주어질때, 사슬에 속해있는 각 객체는 자기가 받은 요청을 검사하여 직접 처리하거나 사슬에 들어있는 다른 객체에 넘기게 되는 방식. 즉 책임을 넘기는 구조입니다.
2. Chain of Responsibility 패턴의 등장인물
- Handler(처리자)의 역할
- 요구를 처리하는 인터페이스(API)를 결정하는 역할을 합니다.
- ConcreteHandler(구체적인 처리자)의 역할
- 요구를 처리하는 구체적인 역할을 합니다.
- Clinet(요구자)의 역할
- 최초의 ConcreteHandler 역할에 요구하는 일을 합니다.
Chain of Responsibility 클래스 다이어 그램
3. 예제
3-1. Trouble 클래스
무언가 요청을 표현할 클래스입니다.
public class Trouble {
private int number;
public Trouble(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
@Override
public String toString() {
return "Trouble [number=" + number + "]";
}
}
3-2. Support 추상 클래스
트러블(요청)을 해결할 사슬을 만들기 위한 추상 클래스입니다. next
라는 필드를 통해서 떠넘기는 곳을 지정하고, 필요하면 트러블(요청)을 떠넘기는 곳을 setNext()
메소드로 설정합니다.
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);
}
}
@Override
public String toString() {
return "Support [name=" + 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");
}
}
support()
메소드를 통해서 트러블(요청)에 대한 처리 수순을 정의했습니다. 또한 실제 처리 부분인 resolve()
메소드는 추상 메소드로 선언해 하위 클래스에서 구체적인 구현을 위임합니다.
3-3. NoSupport, LimitSupport, OddSupport, SpecialSupport 추상 클래스
각각 Support 추상 클래스의 하위 클래스입니다. 필요한 로직을 수행합니다.
public class NoSupport extends Support {
public NoSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {
return false;
}
}
public class OddSupport extends Support {
public OddSupport(String name) {
super(name);
}
@Override
protected boolean resolve(Trouble trouble) {
if(trouble.getNumber() % 2 == 1) {
return true;
}
return false;
}
}
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;
}
return false;
}
}
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;
}
return false;
}
}
3-4. Main 클래스
Support 클래스를 통해 사슬을 생성하고, 트러블(요청)을 수행하는 매인 클래스입니다.
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("Elomo");
Support fred = new LimitSupport("Fred",300);
alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred);
for (int i = 0; i < 500; i++) {
alice.support(new Trouble(i));
}
}
}
실행 결과
Trouble [number=0] is resolved by Support [name=Bob]
Trouble [number=1] is resolved by Support [name=Bob]
Trouble [number=2] is resolved by Support [name=Bob]
....
Trouble [number=498] cannot be resolved
Trouble [number=499] is resolved by Support [name=Elomo]
그렇다면 왜 사용할까?
- 요청을 보낸 쪽하고 받는 쪽을 분리시킬 수 있습니다.
- 객체에서는 사슬의 구조를 몰라도 되고 그 사슬에 들어있는 다른 객체에 대한 직관적인 래퍼런스를 가질 필요도 없기 때문에 객체를 단순하게 만들 수 있습니다.
- 사슬에 들어가는 객체를 바꾸거나 순서를 바꿈으로써 역할을 동적으로 추가/제거할 수 있습니다.
윈도우 시스템에서 마우스 클릭이나 키보드 이벤트를 처리할 때 흔하게 사용됩니다. 그러나 아래와 같은 단점도 존재합니다.
- 실행시에 과정을 살펴보거나 디버깅하기가 힘들 수 있다는 단점이 있습니다.
- 요청이 반드시 수행된다는 보장이 없습니다. 사슬의 끝이여도 어느 객체에서도 처리를 못하는 경우 ( 장점이 될 수도 )
4. 관련 패턴
- Composite 패턴 : Handler 역할에 Composite 패턴이 자주 등장합니다. link
- Command 패턴 : Hanlder 역할에 대해서 제공되는 '요구'에는 Command 패턴이 사용되는 경우가 있습니다.
반응형
'PROGRAMMING > 디자인패턴' 카테고리의 다른 글
[디자인패턴/Design Pattern] Flyweight Pattern / 플라이웨이트 패턴 (0) | 2019.12.31 |
---|---|
[디자인패턴/Design Pattern] Builder 패턴 / 빌더 패턴 (0) | 2019.12.30 |
[디자인패턴/Design Pattern] Bridge Pattern / 브리지 패턴 (0) | 2019.12.26 |
[디자인패턴/Design Pattern] Proxy Pattern / 프록시 패턴 (0) | 2019.12.19 |
[디자인패턴/Design Pattern] State Pattern / 스태이트 패턴 (0) | 2019.12.17 |
Comments