Observer

객체 사이에 일 대 다의 의존 관계를 정의해 두어, 어떤 객체의 상태가 변할 때 그 객체의 의존성을 가진 다른 객체들이 그 변화를 통지받고 자동으로 갱신될 수 있게 만든다.

감시자(observer)는 주체(subject)를 감시하며 주체에 일어난 변경을 통보받는다.

이러한 종류의 상호작용을 게시(publish)-구독(subscribe)관계 라고도 한다. 주체(subject)는 Observed로 표현되기도 한다.

observer-diagram

  • Subject

    Observer들을 알고있는 주체

    Observer의 추가 / 삭제, notify 하는데 필요한 인터페이스를 제공한다.

  • ConcreteSubject

    ConcreteObserver 객체에게 알려주어야 하는 상태를 저장한다.

    상태가 변경될 때 감시자들에게 변경을 통보한다.

  • Observer

    Subject에 생긴 변화에 관심 있는 객체들에게 필요한 인터페이스를 정의한다.

  • ConcreteObserver

    Subject의 상태와 상태와 일관성을 유지해야하는 상태를 저장한다.

    Subject와 해당 Observer의 상태를 일관되게 유지하는데 사용하는 갱신 인터페이스를 구현한다.

Observer 패턴 적용

  • Subject와 ConcreteSubject

    interface Subject {
      state;
      attach: (observer: Observer) => void;
      detach: (observer: Observer) => void;
      notify: () => void;
    }
    
    class CurrentTimeModel implements Subject {
      private observers: Observer[] = [];
      public state: Date;
      attach(observer: Observer) {
        this.observers.push(observer);
      }
      detach(observer: Observer) {
        this.observers = this.observers.filter(
          (currentObserver) => currentObserver != observer
        );
      }
      notify() {
        this.observers.forEach((observer) => observer.update(this));
      }
      changeCurrentTimer() {
        this.state = new Date();
        this.notify();
      }
    }
    

    Subject와 Subject를 구현하는 CurrentTimeModel(ConcreteSubject)이다.

    CurrentTimeModel Observer 패턴의 정의에 따라 attach, detach, notify를 구현하였고 changeCurrentTimer는 CurrentTimeModel의 상태를 변경한 뒤 notify 함수를 호출하여 observer에게 상태의 변화를 알려준다.

  • Observer와 ConcreteObserver

    interface Observer {
      update: (subject: Subject) => void;
    }
    
    class DigitalClock implements Observer {
      update(subject: Subject) {
        console.log(subject.state);
      }
    }
    

    Observer와 Observer를 구현하는 DigitalClock(ConcreteObject)이다.

    update는 CurrentTimeModel의 객체를 전달받아 state를 참조하는 방식으로 Subject의 상태 변화를 감지하여 동작할 수 있다.

  • 사용

    const clockTimer = new ClockTimer();
    const digitalClock1 = new DigitalClock();
    const digitalClock2 = new DigitalClock();
    
    clockTimer.attach(digitalClock1);
    clockTimer.attach(digitalClock2);
    
    clockTimer.changeCurrentTimer();
    

Observer 패턴은 Vanilla JS에서 Frontend 개발할 때, Subject를 모델로 삼고 모델에 저장할 데이터에 의존성이 있는 객체들을 Observer로 두어 개발했던 경험이 있다.

Frontend에서 간단하게 데이터를 상태로 관리할 좋은 패턴이라고 생각한다.