20-책임 연쇄 패턴

책임 연쇄 패턴

개념

책임 연쇄 패턴(Chain of Responsibility): 여러 객체가 요청을 처리할 기회를 가지도록 하여 요청 발신자와 수신자 간의 결합도를 줄인다. 이러한 객체들을 하나의 체인으로 연결하고, 요청을 이 체인을 따라 전달하여 첫 번째로 요청을 처리하는 객체가 이를 처리할 때까지 계속 전달한다.

책임 연쇄의 장점: 고객이 요청을 제출하면 요청은 체인을 따라 전달되어 ConcreteHandler 객체가 처리한다. 수신자와 발신자는 서로에 대한 구체적인 정보를 갖고 있지 않으며, 체인의 각 객체는 체인 구조를 알지 못한다. 결과적으로 책임 연쇄는 객체 간의 연결을 단순화하며, 각 객체는 다음 처리자에 대한 참조만 유지하면 된다. 요청을 처리하는 구조를 언제든지 추가하거나 수정할 수 있어 객체에 대한 책임 할당의 유연성을 높인다. 주의할 점은 요청이 체인의 끝까지 도달했지만 처리되지 않거나, 잘못된 구성으로 인해 처리되지 않을 수 있다는 것이다.

예제

관리자들이 휴가 및 급여 인상 요청을 처리하는 시나리오

package com.gof.chainOfResponsibility;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 요청 정보를 담는 클래스
 *
 * @since 2023-03-01
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Application {
    private String category;

    private int days;

    private String reason;
}
package com.gof.chainOfResponsibility;

/**
 * 관리자의 추상 클래스
 *
 * @since 2023-03-01
 */
public abstract class Supervisor {
    private String supervisorName;

    public Supervisor(String name) {
        this.supervisorName = name;
    }

    private Supervisor nextLevel;

    public void setNextLevel(Supervisor level) {
        this.nextLevel = level;
    }

    public Supervisor getNextLevel() {
        return nextLevel;
    }

    public String getName() {
        return supervisorName;
    }

    public abstract void process(Application application);
}
package com.gof.chainOfResponsibility;

import java.util.Objects;

/**
 * 일반 관리자 클래스
 *
 * @since 2023-03-01
 */
public class RegularManager extends Supervisor {

    public RegularManager(String name) {
        super(name);
    }

    @Override
    public void process(Application application) {
        if (application.getCategory().equals("휴가") && application.getDays() <= 2) {
            System.out.printf("%s: %s %d 일, 승인됨.\n", getName(), application.getReason(), application.getDays());
        } else {
            if (Objects.nonNull(getNextLevel())) {
                getNextLevel().process(application);
            }
        }
    }
}
package com.gof.chainOfResponsibility;

import java.util.Objects;

/**
 * 주임 관리자 클래스
 *
 * @since 2023-03-01
 */
public class DeputyManager extends Supervisor {
    public DeputyManager(String name) {
        super(name);
    }

    @Override
    public void process(Application application) {
        if (application.getCategory().equals("휴가") && application.getDays() < 5) {
            System.out.printf("%s: %s %d 일, 승인됨.\n", getName(), application.getReason(), application.getDays());
        } else {
            if (Objects.nonNull(getNextLevel())) {
                getNextLevel().process(application);
            }
        }
    }
}
package com.gof.chainOfResponsibility;

/**
 * 총괄 관리자 클래스
 *
 * @since 2023-03-01
 */
public class ExecutiveManager extends Supervisor {
    public ExecutiveManager(String name) {
        super(name);
    }

    @Override
    public void process(Application application) {
        if (application.getCategory().equals("휴가")) {
            System.out.printf("%s: %s %d 일, 승인됨.\n", getName(), application.getReason(), application.getDays());
        } else if (application.getCategory().equals("급여 인상")) {
            if (application.getDays() <= 500) {
                System.out.printf("%s: %s %d 원, 승인됨.\n", getName(), application.getReason(), application.getDays());
            } else {
                System.out.printf("%s: %s %d 원, 검토 필요.\n", getName(), application.getReason(), application.getDays());
            }
        }
    }
}
package com.gof.chainOfResponsibility;

/**
 * 클라이언트 코드
 *
 * @since 2023-03-01
 */
public class DemoClient {
    public static void main(String[] args) {
        // 관리자 계층 구성
        RegularManager regular = new RegularManager("팀장");
        DeputyManager deputy = new DeputyManager("부서장");
        ExecutiveManager executive = new ExecutiveManager("이사");
        regular.setNextLevel(deputy);
        deputy.setNextLevel(executive);

        // 요청 생성
        Application app1 = new Application("휴가", 2, "회의 참석");
        Application app2 = new Application("휴가", 4, "가족 방문");
        Application app3 = new Application("급여 인상", 500, "성과 보상");
        Application app4 = new Application("급여 인상", 1000, "특별 보상");

        regular.process(app1);
        regular.process(app2);
        regular.process(app3);
        regular.process(app4);
    }
}

태그: java design-pattern chain-of-responsibility software-design object-oriented-programming

8월 7일 10:59에 게시됨