1. 책임 연쇄 패턴(Chain of Responsibility pattern)

책임 연쇄 패턴은 핸들러들의 체인(사슬)을 따라 요청을 전달할 수 있게 해주는 행동 디자인 패턴이다. 각 핸들러는 요청을 받으면 요청을 처리할지 또는 체인의 다음 핸들러로 전달할지 결정한다.

 

책임 연쇄 패턴을 사용하면 SRP 를 지킬 수 있다. SRP 는 객체는 단 하나의 책임을 가져야 한다는 원칙이다. 즉, 변경되어야 할 이유 또한 한가지여야 한다는 의미이다. 책임 연쇄 패턴을 사용하면 각 핸들러에게 책임을 맡기고 핸들러 책임 외에는 다른 핸들러에게 위임하기 때문에 SRP 를 지킬 수 있다.

 

책임 연쇄 패턴은 요청을 보내는 주체와 요청을 처리하는 주체를 분리하는 패턴으로 요청을 보내는 주체가 요청을 처리하는 핸들러가 구체적인 타입에 상관없이 디커플링 된 상태에서 처리 가능하도록 해주는 패턴이다.

sample code : Client

class Main {
	public static void main(String[] args) {
		RequestHandler chainingRequestHandler =
			new RequestHandler(
				new RequestUuidHandler(
					new RequestLoggingHandler(null)));

		final Client client = new Client(chainingRequestHandler);
		client.doWork("hello request");
	}

}

class Client {

	private final RequestHandler requestHandler;

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

	void doWork(final String request) {
		requestHandler.handle(request);
	}

}

 

sample code : RequestHandler Chaining

// RequestHandler
public class RequestHandler {

	private RequestHandler nextHandler;

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

	public void handle(String request) {
		nextHandler.handle(request);
	}
}

// RequestLoggingHandler
public class RequestLoggingHandler extends RequestHandler {

	private RequestHandler nextHandler;

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

	@Override
	public void handle(final String request) {
		System.out.println("2. request logging start ======================");

		System.out.println("logging request : " + request);

		System.out.println("2. request logging end ======================");
		if (nextHandler == null) {
			return;
		}

		super.handle(request);

	}

}

// RequestUuidHandler
public class RequestUuidHandler extends RequestHandler {

	private RequestHandler nextHandler;

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

	@Override
	public void handle(final String request) {
		System.out.println("1. request uuid start ======================");

		UUID uuid = UUID.randomUUID();
		System.out.println("request uuid : " + uuid.toString());

		super.handle(request);
		System.out.println("1. request uuid end ======================");
	}
}

 

Result

 

2. 책임 연쇄 패턴의 장단점

책임 연쇄 패턴의 장점은 SRP 를 지키면서 기능을 추가할 수 있다. 새로운 기능을 추가하고 싶은 경우 새로운 핸들러를 등록하고 순서를 결정하면 클라이언트 코드 변경없이 기능을 추가할 수 있다.

 

그리고 요청의 처리 순서를 제어하고 특정 요청에 한해서만 실행 가능하도록 설정이 가능하다. 하지만 특정 요청이 처리되지 않을 수 있기 때문에 주의해야 한다.

 

단점은 디버깅이 번거롭다. filter chaining 을 통한 핸들러가 증가하면 원하는 핸들러를 찾기 위해 체이닝 되어 있는 핸들러를 탐색해야 하기 때문에 번거롭다.

 

3. 책임 연쇄 패턴 예시

스프링 시큐리티에서 filter chain 를 기반해서 인증, 인가 기능을 제공한다.

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	// do something before the rest of the application
	chain.doFilter(request, response); // invoke the rest of the application
	// do something after the rest of the application
}

 

Reference

'java > summary' 카테고리의 다른 글

퍼사드 패턴(Facade Pattern)  (0) 2024.07.08
커맨드 패턴(command pattern)  (0) 2024.07.08
싱글톤 패턴(singleton pattern)  (0) 2024.07.03
정밀 연산에는 BigDecimal 을 사용하자  (0) 2024.04.24
Garbage Collector simple summary  (0) 2024.03.04