자바 디자인 패턴

14. Chain of Responsibility - 책임을 떠넘긴다

조요피 2023. 10. 19. 09:01

14. Chain of Responsibility - 책임을 떠넘긴다

Chain of Responsibility 패턴은 객체 지향 소프트웨어 디자인 패턴 중 하나로, 요청을 처리하는 객체들의 연결된 체인을 만들어 처리 과정을 단순화하고 유연성을 제공하는 패턴입니다. 이 패턴은 요청을
만드는 객체와 요청을 처리하는 객체를 분리하여 객체 간의 결합도를 낮추고, 요청을 처리하는 객체를 동적으로 변경하거나 확장할 수 있도록 해줍니다.

Chain of Responsibility 패턴은 주로 다음과 같은 상황에서 사용됩니다:

  1. 요청을 여러 단계로 나눠 처리해야 하는 경우.
  2. 요청을 처리할 수 있는 객체가 동적으로 변경되어야 하는 경우.
  3. 요청을 처리할 수 있는 객체를 동적으로 확장하고 조합해야 하는 경우.

패턴의 주요 구성 요소는 다음과 같습니다:

  1. Handler (처리자) 인터페이스 또는 추상 클래스: 요청을 처리할 수 있는 메서드를 정의하는 인터페이스 또는 추상 클래스입니다.

  2. ConcreteHandler (구체적인 처리자): Handler 인터페이스나 추상 클래스를 구현한 구체적인 처리자 객체입니다. 이 객체는 요청을 처리할 수 있는지를 판단하고, 처리할 수 있다면 요청을 처리하거나
    다음 처리자에게 요청을 전달합니다.

  3. Client (클라이언트): 요청을 만들고 처리할 Handler 객체를 체인의 시작점에 연결하는 역할을 하는 객체입니다.

  4. Chain (체인): 여러 ConcreteHandler 객체가 연결되어 있는 구조로, 클라이언트가 요청을 만들면 체인의 시작점부터 끝까지 순차적으로 요청을 처리하거나 전달합니다.

패턴 동작의 일반적인 순서는 다음과 같습니다:

  1. 클라이언트가 요청을 생성합니다.
  2. 요청은 체인의 시작점에 있는 ConcreteHandler 객체로 전달됩니다.
  3. ConcreteHandler 객체는 요청을 처리할 수 있는지 판단하고 처리 가능하다면 처리하고, 그렇지 않으면 다음 처리자에게 요청을 전달합니다.
  4. 이 과정은 요청이 처리될 때까지 반복됩니다.

이렇게 하면 여러 객체가 연결된 체인을 통해 요청을 처리할 수 있고, 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에게 전달됩니다. 이렇게 함으로써 휴가 요청을 순차적으로
처리하며, 체인의 끝에 도달할 때까지 처리를 시도합니다.