14. Chain of Responsibility - 책임을 떠넘긴다
14. Chain of Responsibility - 책임을 떠넘긴다
Chain of Responsibility 패턴은 객체 지향 소프트웨어 디자인 패턴 중 하나로, 요청을 처리하는 객체들의 연결된 체인을 만들어 처리 과정을 단순화하고 유연성을 제공하는 패턴입니다. 이 패턴은 요청을
만드는 객체와 요청을 처리하는 객체를 분리하여 객체 간의 결합도를 낮추고, 요청을 처리하는 객체를 동적으로 변경하거나 확장할 수 있도록 해줍니다.
Chain of Responsibility 패턴은 주로 다음과 같은 상황에서 사용됩니다:
- 요청을 여러 단계로 나눠 처리해야 하는 경우.
- 요청을 처리할 수 있는 객체가 동적으로 변경되어야 하는 경우.
- 요청을 처리할 수 있는 객체를 동적으로 확장하고 조합해야 하는 경우.
패턴의 주요 구성 요소는 다음과 같습니다:
Handler (처리자) 인터페이스 또는 추상 클래스: 요청을 처리할 수 있는 메서드를 정의하는 인터페이스 또는 추상 클래스입니다.
ConcreteHandler (구체적인 처리자): Handler 인터페이스나 추상 클래스를 구현한 구체적인 처리자 객체입니다. 이 객체는 요청을 처리할 수 있는지를 판단하고, 처리할 수 있다면 요청을 처리하거나
다음 처리자에게 요청을 전달합니다.Client (클라이언트): 요청을 만들고 처리할 Handler 객체를 체인의 시작점에 연결하는 역할을 하는 객체입니다.
Chain (체인): 여러 ConcreteHandler 객체가 연결되어 있는 구조로, 클라이언트가 요청을 만들면 체인의 시작점부터 끝까지 순차적으로 요청을 처리하거나 전달합니다.
패턴 동작의 일반적인 순서는 다음과 같습니다:
- 클라이언트가 요청을 생성합니다.
- 요청은 체인의 시작점에 있는 ConcreteHandler 객체로 전달됩니다.
- ConcreteHandler 객체는 요청을 처리할 수 있는지 판단하고 처리 가능하다면 처리하고, 그렇지 않으면 다음 처리자에게 요청을 전달합니다.
- 이 과정은 요청이 처리될 때까지 반복됩니다.
이렇게 하면 여러 객체가 연결된 체인을 통해 요청을 처리할 수 있고, ConcreteHandler 객체를 동적으로 추가하거나 제거하여 처리 과정을 확장하거나 변경할 수 있습니다.
예제 코드
간단한 Java 예제로 Chain of Responsibility 패턴을 구현해보겠습니다. 이 예제에서는 휴가 신청 처리를 예시로 사용하겠습니다. 각 ConcreteHandler는 다른 유형의 휴가 요청을 처리할 수
있고, 체인을 통해 요청이 처리됩니다.
먼저 Handler 인터페이스를 정의합니다:
public interface VacationRequestHandler {
void handleRequest(VacationRequest request);
void setNextHandler(VacationRequestHandler nextHandler);
}
다음으로, ConcreteHandler 클래스를 구현합니다:
public class Manager implements VacationRequestHandler {
private VacationRequestHandler nextHandler;
@Override
public void handleRequest(VacationRequest request) {
if (request.getDays() <= 3) {
System.out.println("Manager can approve " + request.getDays() + " days of vacation for " + request.getEmployeeName());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("No one can approve " + request.getDays() + " days of vacation for " + request.getEmployeeName());
}
}
@Override
public void setNextHandler(VacationRequestHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
public class HR implements VacationRequestHandler {
private VacationRequestHandler nextHandler;
@Override
public void handleRequest(VacationRequest request) {
if (request.getDays() <= 7) {
System.out.println("HR can approve " + request.getDays() + " days of vacation for " + request.getEmployeeName());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("No one can approve " + request.getDays() + " days of vacation for " + request.getEmployeeName());
}
}
@Override
public void setNextHandler(VacationRequestHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
VacationRequest 클래스는 요청을 나타내는 클래스로, 여기에서는 휴가 일수와 직원 이름을 포함합니다.
public class VacationRequest {
private int days;
private String employeeName;
public VacationRequest(int days, String employeeName) {
this.days = days;
this.employeeName = employeeName;
}
public int getDays() {
return days;
}
public String getEmployeeName() {
return employeeName;
}
}
마지막으로, 클라이언트 코드를 작성하여 체인을 생성하고 휴가 요청을 처리합니다:
public class Client {
public static void main(String[] args) {
VacationRequestHandler manager = new Manager();
VacationRequestHandler hr = new HR();
manager.setNextHandler(hr);
VacationRequest request1 = new VacationRequest(2, "John");
VacationRequest request2 = new VacationRequest(5, "Alice");
VacationRequest request3 = new VacationRequest(10, "Bob");
manager.handleRequest(request1);
manager.handleRequest(request2);
manager.handleRequest(request3);
}
}
위의 예제에서, Manager와 HR는 각각 휴가 요청을 처리할 수 있는 ConcreteHandler입니다. Manager가 처리할 수 없는 요청은 HR에게 전달됩니다. 이렇게 함으로써 휴가 요청을 순차적으로
처리하며, 체인의 끝에 도달할 때까지 처리를 시도합니다.