반응형

의도

  • 요청을 보내는 쪽(sender)과 요청을 처리하는 쪽(receiver)을 분리하는 패턴
  • 메시지를 보내는 객체와 이를 받아 처리하는 객체들 간의 결합도를 없애기 위한 패턴
  • 하나의 요청에 대한 처리가 반드시 한 객체에서만 되지 않고, 여러 객체에게 그 처리 기회를 주려는 것

 

장점

  • 클라이언트 코드를 변경하지 않고 새로운 핸들러를 체인에 추가할 수 있다.
  • 각각의 체인은 자신이 해야하는 일만 한다.
  • 체인을 다양한 방법으로 구성할 수 있다.

 

단점

  • 코드의 흐름이 많아져서 디버깅이 조금 어렵다.
  • 메시지가 처리되지 않을 수도 있다.

 

알려진 사용 예

  • 자바
    • 서블릿 필터
  • 스프링
    • 스프링 시큐리티 필터

 

활용성

  • 하나 이상의 객체가 요청을 처리해야 하고, 그 요청 처리자 중 어떤 것이 선행자(priori)인지 모를 때. 처리자가 자동으로 확정되어야 한다.
  • 메시지를 받을 객체를 명시하지 않은 채 여러 객체 중 하나에게 처리를 요청하고 싶을 때
    • 메시지를 받을 객체를 구체화하지 않고 처리를 요청할 수 있다.
  • 요청을 처리할 수 있는 객체 집합이 동적으로 정의되어야 할 때

 

결과

  • 객체 간의 행동적 결합도가 적어진다.
  • 객체에게 책임을 할당하는 데 유연성을 높일 수 있다.
  • 메시지 수신이 보장되지는 않는다. 즉, 요청 처리가 안될수도 있다.

 

협력 방법

  • 사용자는 처리를 요청하고, 이 처리 요청은 실제로 그 요청을 받을 책임이 있는 ConcreteHandler 객체를 만날 때까지 정의된 연결 고리를 따라서 계속 전달된다.
  • 핸들러 체인을 사용해서 요청을 처리한다.

 

구조

  • 객체 다이어그램

 

실제 구현 구조

소스코드

public class Client {

    //클라이언트 코드 영역
    private final RequestHandler requestHandler;

    public Client(RequestHandler requestHandler) {
        this.requestHandler = requestHandler;
    }

    public void doWork() {
        Request request = new Request("이번 놀이는 뽑기입니다.");
        requestHandler.handleRequest(request);
    }
    //클라이언트 코드 영역 종료
    //main 위에까지만 클라이언트라고 생각하자.
    public static void main(String[] args) {
        //체인 조립, 이 작업은 외부에서 해도된다.
        RequestHandler chain = new AuthRequestHandler(new LoggingRequestHandler(new PrintRequestHandler(null)));

        //클라이언트에서 처리 요청
        Client client = new Client(chain);
        client.doWork();
    }
}
//필드가 필요하기 때문에 추상 클래스로 만든다.
public abstract class RequestHandler {
    private final RequestHandler nextHandler;

    public RequestHandler(RequestHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handleRequest(Request request) {
        if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }else {

        }
    }
}
public class AuthRequestHandler extends RequestHandler {

    public AuthRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handleRequest(Request request) {
        System.out.println("인증이 되었는지 확인");
        super.handleRequest(request);
    }
}
public class LoggingRequestHandler extends RequestHandler {

    public LoggingRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handleRequest(Request request) {
        System.out.println("로깅");
        super.handleRequest(request);
    }
}
public class PrintRequestHandler extends RequestHandler {

    public PrintRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handleRequest(Request request) {
        System.out.println(request.getBody());
        super.handleRequest(request);
    }
}

 

관련 패턴

  • 책임 연쇄 패턴은 복합체 패턴과 함께 대부분 사용되는데, 이 때 구성요소의 부모는 후속 처리자처럼 동작한다.

 


[참고자료]

리처드 헬름, 랄프 존슨, 존 블리시디스, 『GoF의 디자인 패턴 : 재사용성을 지닌 객체지향 소프트웨어의 핵심요소』, 김정아 번역, 프로텍미디어(2015)

http://www.cs.unc.edu/~stotts/GOF/hires/pat5afso.htm

코딩으로 학습하는 GoF의 디자인 패턴, 백기선

반응형

+ Recent posts