본문 바로가기

취업과 기본기 튼튼/빽 투더 기본기

[디자인 패턴 14편] 행동 패턴, 책임 연쇄 (Chain of responsibility)

1. 개념

책임 연쇄 패턴은 요청을 처리하는 동일 인터페이스 객체들을
체인 형태로 연결해놓는 패턴이다.

앞의 객체의 요청을 처리하지 못할 경우, 같은 인터페이스의 다른 객체에게 해당 요청을 전달한다.

1.1. 구조

  • Handler
    • 요청을 처리하는 목적의 추상 클래스
    • ConcreteHandler 가 이를 상속받아 HandleRequest() 를 구현한다.
  • ConcreteHandler
    • Handler 를 상속받아 요청 처리를 구현하는 구체적인 클래스

1.2. 장단점

  • 이것도 역시 상황에 맞게 사용되는거라 딱히 장단점을 말할 수 는 없을 듯?

1.3. 활용 상황

  • 말 그대로 객체가 동일한 인터페이스(기능)을 갖되
  • 요청을 처리는데, 이 요청을 처리하지 못할 시, 이걸 처리해줄 그 다음 객체를 지정해야 할 때.
  • 요청을 처리하는 '순서'를 가짐.

2. 구현

클라이언트는 다음과 같이 사용할 수 있다.

concrete_handler_1 = ConcreteHandler1()
concrete_handler_2 = ConcreteHandler2(concrete_handler_1)

# concrete_handler_1 -> concrete_handler_2 순으로 처리.
concrete_handler_2.handle_request()

구체적인 ConcreteHandler 가 구현해야하는 추상 클래스는 다음과 같다.

class Handler(metaclass=ABCMeta):
    def __init__(self, successor:Handler = None) -> None:
        # 연결해놓을 클래스를 successor 에 달아둔다.
        self._successor = successor

    @abstractmethod
    def can_handle(self) -> bool:
        # 여기에 해당 클래스가 처리할 수 있는지 여부를 반환.
        pass

    @abstractmethod
    def handle_request(self) -> None:
        pass

Handler 를 상속받아 구체적인 Handler 객체를 정의하는 ConcreteHandler 들은 다음과 같다.

class ConcreteHandler1(Handler):
    def can_handle(self):
        return False

    def handle_request(self):
        if can_handle():
            # 처리 가능하면 여기서 처리하면 됨.
        elif self._successor is not None:
            # 처리 불가능한 경우, 다음 클래스 동작.
            self._successor.handle_request()

class ConcreteHandler1(Handler):
    def can_handle(self):
        return True

    def handle_request(self):
        if can_handle():
            pass
        elif self._successor is not None:
            self._successor.handle_request()

3. 참고