Chain of Responsibility 메서드 체이닝

고승원·2022년 10월 20일
0

Design Pattern

목록 보기
3/5
post-thumbnail


핸들러를 따라 요청을 전달할 수 있는 디자인 패턴. 요청을 받으면 각 핸들러는 요청을 처리할지 다음 체인으로 전달할지 결정한다.

사용처

  • 순차적인 검증에서 실패하면 다른 검사를 진행할 이유가 없을 때
  • 각각의 검증 코드를 재사용할 때

장점

  • 추가적인 처리가 필요 없을 때 효과적으로 중지할 수 있다.
  • 요청 처리 순서를 제어할 수 있다.
  • SRP
  • OCP

단점

  • 일부 요청을 처리되지 않을 수 있다.

구현

모든 핸들러 클래스가 동일한 인터페이스를 구현하는 것이 중요하다. 세부 핸들러는 메서드가 있는 다음 핸들러만 신경을 써야한다.

Handler : 모든 구체적인 핸들러의 공통 인터페이스. 일반적으로 단일메서드만 포함하지만, 다음 핸들러를 설정하기 위한 메서드가 포함되기도 한다.

BaseHandler : 모든 핸들러 클래스에 공통적인 코드를 선택적인 클래스다. 일반적으로는 다음 핸들러에 대한 참조를 저장하기 위해 사용한다. 클라이언트는 이전 핸들러의 생성자나 setter를 통해 체인을 구출할 수 있다.

ConcreateHandlers : 요청을 처리하기 위한 실제 코드. 각 핸들러는 요청을 처리할지 여부와 함께 체인에 전달할지 결정한다.

Client : 체인을 한 번만 구성할지 동적으로 구성할지 결정할 수 있다. 요청은 모든 핸들러에게 보낼 수 있다.

  1. handler interface를 선언하고 요청 처리하는 메서드를 선언한다.
  2. ConcreateHandlers에서 중복된 코드를 제거하려면 BaseHandler를 사용하는 것이 좋다.
  3. 구체적인 구현을 한다. 각 핸들러는 두가지 결정을 한다.
    • 요청을 처리할지.
    • 체인을 따라 요청을 전달할지.
  4. 클라이언트는 체인을 호출하거나 다를 객체에서 체인을 호출할 수 있다.

코드

Handler

 interface MyIterator <T>{
     boolean hasNext();
 
     T next();
 }

BaseHandler

  public MyIterator<T> iterator() {
          return new MyIterator<T>() {
              private int index=0;
              @Override
              public boolean hasNext() {
                  return index<list.size();
              }
  
              @Override
              public T next() {
                  return list.get(index++);
              }
          };
      }

ConcreateHandler

 public class MyCollection<T> {
     private List<T> list;
 
     public MyCollection(List<T> list) {
         this.list = list;
     }
 
     public <U> MyCollection<U> map(Function<T, U> function) {
         List<U> newList = new ArrayList<>();
         foreach(d -> newList.add(function.apply(d)));
         return new MyCollection<>(newList);
     }
 
     public MyCollection<T> filter(Predicate<T> predicate) {
         List<T> newList = new ArrayList<>();
         foreach(d -> {
             if (predicate.test(d)) newList.add(d);
         });
         return new MyCollection<>(newList);
     }
 
     public int size() {
         return list.size();
     }
 
     public void foreach(Consumer<T> consumer) {
         for (int i=0; i<list.size(); i++){
             T data = list.get(i);
             consumer.accept(data);
         }
     }

Client

 int s = new MyCollection<>(Arrays.asList("a","ab", "abc", "abcd","abcde"))
                 .map(String::length)
                 .filter(i -> i%2 == 0)
                 .size();
 
 //메서드 체이닝 사용

chain of responsiility는 decorator와 구조가 매우 비슷하다.

profile
봄은 영어로 스프링

0개의 댓글