Design Pattern_Behavioral_Chain-of-Responsibility

박지홍·4일 전

DesignPattern

목록 보기
6/8
post-thumbnail

책임 연쇄 패턴(Chain-of-Responsibility)

요청을 보내는 쪽(Sender)과 요청을 처리하는 쪽(Receiver)을 분리하는 패턴

  • 핸들러 체인을 사용하여 요청을 처리한다.
    => 첫 사람이 보고 자기가 할 수 있는 일을 하고, 그다음 사람에게 넘기고 또 다음 사람이 이어서 처리하고 마지막 사람이 끝낸다는 구조
  • Chain = 사슬 처럼 연결 됨, Responsibility = 각자 맡은 책임이 있음.

적용

before

  1. Request
public class Request {

    private String body;

    public Request(String body) {
        this.body = body;
    }

    public String getBody() {
        return body;
    }
}
  1. RequestHandler
public class RequestHandler {

    public void handler(Request request) {
        System.out.println(request.getBody());
    }
}

기본 처리자, 그저 요청 내용 출력

  1. LoggingRequestHandler
public class LoggingRequestHandler extends RequestHandler {

    @Override
    public void handler(Request request) {
        System.out.println("로깅");
        super.handler(request);
    }
}

(1) 로깅을 출력하고, (2) 부모의 handler() 호출 (요청 본문 출력)

  1. AuthRequestHandler
public class AuthRequestHandler extends RequestHandler {

    public void handler(Request request) {
        System.out.println("인증이 되었나?");
        System.out.println("이 핸들러를 사용할 수 있는 유저인가?");
        super.handler(request);
    }
}

(1) 인증 검사, (2) 부모의 handler() 호출 (요청 본문 출력)

  • 문제점 : 인증도 하고 로깅도 하고 출력도 하고 싶은데 유연하게 조립하기 어렵다. 또한 로깅과 인증의 순서가 매번 다를 수 있다. 기능 추가도 깔끔하지 못함.

after

public static void main(String[] args) {
    RequestHandler chain = new AuthRequestHandler(
        new LoggingRequestHandler(
            new PrintRequestHandler(null)
        )
    );
    Client client = new Client(chain);
    client.doWork();
}

연결구조 : Auth-> Logging -> Print

  1. client.dowork() 안에서 다음 실행
Request request = new Request("이번 놀이는 뽑기입니다.");
requestHandler.handle(request);
  1. AuthRequestHandler 실행
System.out.println("인증이 되었는가?");
super.handle(request);
  1. LoggingRequestHandler 실행
  2. PrintRequestHandler 실행

각 객체는 자기 책임만 처리한다.

장단점

  • 장점
    - 클라이언트 코드를 변경하지 않고 새로운 핸들러를 체인에 추가하기가 편리하다.
    • 각각의 체인은 자신이 해야하는 일만 한다.
    • 체인의 순서를 쉽게 바꿀 수 있다.
  • 단점
    - 체인이 길어지면 흐름 파악이 어렵기 때문에 디버깅이 어려워진다.

자바와 스프링에서 예제 찾기

ex1) 서블릿 필터체인

@WebFilter(urlPatterns = "/hello")
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("게임에 참하신 여러분 모두 진심으로 환영합니다.");
        chain.doFilter(request, response);
        System.out.println("꽝!");
    }
}

chain.doFilter(request, response); => 다음 필터나 다음 처리 단계로 넘기기

  1. 클라이언트가 /hello 요청 보냄
  2. MyFilter가 먼저 잡음
  3. "게임에 참하신 여러분 모두 진심으로 환영합니다." 출력
  4. chain.doFilter(...) 호출
  5. 다음 단계로 넘어감
  6. 최종적으로 HelloController 실행
  7. 다시 돌아와서 "꽝!" 출력

ex2) 스프링 필터
1. 인증 필터
2. 로깅 필터
3. CORS 필터
4. 인코딩 필터

0개의 댓글