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

[디자인 패턴 12편] 행동 패턴, 옵저버(Observer)

흠시 2020. 3. 21. 16:53

1. 개념

옵저터 패턴은 하나의 관찰대상 - 여러 개의 관찰자 구조가 필요할 때 쓰는 패턴이다.

1.1. 구조

  • Subject
    • 관찰 대상이 되는 객체
    • 자신을 관찰하는 옵저버들 리스트를 가지고 관리도 함.
      • 옵저버 붙이기(attach), 떼기(detach), 알리기(notfiy) 를 가지고 있어야 함.
  • Observer
    • Subject 를 관찰하는 객체
    • Subejct 가 notify 를 호출하면 Observer 의 update 도 호출됨.
      • Observer.update() 에 관찰 대상이 notify 했을 때의 할 일들을 적으면 됨.

1.2. 장단점

  • 딱히 장단점 가릴게 없는 패턴인거 같다.
  • 필요에 따라 쓰는 패턴.

1.3. 활용 상황

  • 관찰대상 - 관찰자의 구조를 가질 때 쓰면 된다.
  • 이벤트 핸들러가 대표적인 옵저버 패턴의 예다.
    • 이벤트 핸들러 : Observer
    • 이벤트 : Subject

2. 구현

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

# 관찰 대상
subject = ConcreteSubject()

# 관찰할 옵저버를 만들고, 관찰 대상에 옵저버를 붙인다.
observer_a = ConcreteObserverA()
subject.attach(observer_a)

observer_b = ConcreteObserverB()
subject.attach(observer_b)

# 관찰 대상은 자기 할일 함. 이때 마다 전파!
subject.some_business_logic()

# 관찰 대상에서 옵저버를 뗀다.
subject.detach(observer_a)

관찰 대상인 subject 는 다음 클래스로 정의된다.

class Subject():
    def __init__(self) -> None:
        self._observers = []

    def attach(self, observer: Observer) -> None:
        self._observers.append(observer)

    def detach(self, observer: Observer) -> None:
        self._observers.remove(observer)

    def notify(self) -> None:
        for observer in self._observers:
            observer.update(self)

    def some_business_logic(self) -> None:
        # 어떤 필요한 로직을 진행 
        # 이후 자신을 관찰하고 있는 옵저버들에게 알림.
        self.notify()

관찰하는 대상인 observer 는 다음과 같이 정의된다.

class Observer(metaClass=ABCMeta):
    @abstractmethod
    def update(self, subject: Subject) -> None:
        pass
class ConcreteObserverA(Observer):
    def update(self, subject: Subject) -> None:
        # 관찰 중인 대상을 파라미터로 받아, 해야하는 일 처리.

class ConcreteObserverB(Observer):
    def update(self, subject: Subject) -> None:
        # 관찰 중인 대상을 파라미터로 받아, 해야하는 일 처리.

3. 참고