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

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

흠시 2020. 3. 21. 18:55

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. 참고