디자인패턴

옵저버 패턴 (Observer Pattern)

traveler_JH 2024. 12. 14. 22:38

옵저버 패턴 (Observer Pattern)

    • 객체의 상태 변화(Subject)를 감지하고, 그 변화에 반응해야하는 다수의 객체(Observer)에 이를 자동으로 통보하는 디자인 패턴
    • 즉, 하나의 객체(Subject)가 변할때 연결된 다른 객체들(Observer)에게 자동으로 변화가 통지 되고 동작하도록 설계한것

전략 패턴의 핵심

    • Subject
      • 상태를 관리하면 상태변화가 발생하면 옵저버들에게 이를 알린다.
    • Observer
      • Subject를 구독하여 상태변화를 감지하고 알림을 받으면 특정 작업을 수행
    • 객체간 느슨한결합(loose coupling)을 유지하면서도 상태 변경에 따른 반응을 자동화한다.

구성요소

    • Subject
      • 관찰되는 객체로, 상태를 관리하며, 옵저버들을 등록/제거하고 상태 변화시 통보
    • Observer
      • Subject를 관찰하는 객체로 Subject의 상태 변화에 반응
    • Observer list
      • Subject는 자신의 상태를 감시하고 있는 옵저버들의 목록

예제 - 뉴스 구독

// Subject (주체)
class NewsPublisher {
    constructor() {
        this.observers = []; // 옵저버 목록 
    }

    subscribe(observer) {
        this.observers.push(observer); // 옵저버 등록 //this.observers 배열에 옵저버를 추가
    }

    unsubscribe(observer) {
        this.observers = this.observers.filter((obs) => obs !== observer); // 옵저버 제거 // filter 메서드를 사용하여 옵저버 목록에서 해당 옵저버를 제거
    }

    notify(news) {
        this.observers.forEach((observer) => observer.update(news)); // 배열의 옵저버들에게 알림 // 각 옵저버의 update(news) 메서드를 호출
    }
}

// Observer (옵저버)
class Subscriber {
    constructor(name) {
        this.name = name;
    }

    update(news) {
        console.log(`${this.name} received news: ${news}`); //Subject로부터 전달된 뉴스(알림)를 받아 실행
    }
}

// 클라이언트 코드
const publisher = new NewsPublisher(); // publisher는 NewsPublisher의 인스턴스(주체)

//subscriber1과 subscriber2는 각각 Subscriber의 인스턴스(옵저버)
const subscriber1 = new Subscriber("Alice"); 
const subscriber2 = new Subscriber("Bob");

// 옵저버 등록
publisher.subscribe(subscriber1);
publisher.subscribe(subscriber2);
//publisher는 두 옵저버(subscriber1, subscriber2)에게 상태 변화를 통보할 준비 완료

// 뉴스 발행
publisher.notify("Breaking News: Observer Pattern Explained!"); //notify 호출 -> 등록된 모든 옵저버의 update(news)매서드 실행
//실행결과
//Alice received news: Breaking News: Observer Pattern Explained!
//Bob received news: Breaking News: Observer Pattern Explained!

// 옵저버 제거 후 뉴스 발행
publisher.unsubscribe(subscriber1);
publisher.notify("More News: Observer Pattern in JavaScript!");
//실행결과
//Bob received news: More News: Observer Pattern in JavaScript!
 

작동 방식

  • NewsPublisher (Subject):
    • 옵저버(구독자) 목록을 관리하며, 상태 변화(뉴스 발행)가 발생하면 구독자들에게 알림을 보낸다.
    • subscribe(observer): 옵저버를 등록.
    • unsubscribe(observer): 옵저버를 제거.
    • notify(news): 모든 등록된 옵저버들에게 상태 변화(뉴스)를 알린다.
  • Subscriber (Observer):
    • 뉴스 발행 시 Subject로부터 알림을 받고, update(news) 메서드를 통해 해당 알림을 처리
  • 클라이언트 코드:
    • Subject와 Observer 간의 관계를 설정.
    • Subject의 상태가 변경될 때, Observer는 자동으로 알림을 받고 반응.

옵저버 패턴의 장점

  1. 느슨한 결합(Loose Coupling):
    • Subject와 Observer 간의 의존성이 낮습니다.
    • Subject는 자신의 상태를 알리기만 하고, Observer가 어떤 작업을 수행하는지 알 필요가 없다.
  2. 자동 알림:
    • Subject의 상태 변화가 자동으로 Observer에 통지되므로, 수동으로 상태를 확인하거나 데이터를 동기화할 필요가 없다.
  3. 확장성:
    • 새로운 Observer를 추가하거나 제거해도 Subject의 코드에는 영향을 미치지 않는다.

옵저버 패턴의 단점

  • 성능 문제:
    • 옵저버의 수가 많아지면, 상태 변화 시 모든 옵저버에게 알림을 보내는 비용이 증가할 수 있다.
  • 디버깅 어려움:
    • Subject와 Observer 간의 상호작용이 복잡해질수록 디버깅과 테스트가 어려워질 수 있다.
  • 예상치 못한 동작:
    • Observer가 Subject의 상태 변화에 대해 적절히 반응하지 않으면, 예상치 못한 결과를 초래할 수 있다.

옵저버 패턴이 적합한 상황

  1. 상태 변화와 관련된 동작이 여러 객체에 영향을 미칠 때:
    • 예: GUI 이벤트 시스템, 알림 시스템.
  2. 여러 객체가 동일한 데이터를 참조하거나 동기화해야 할 때:
    • 예: 데이터 모델과 UI 간의 동기화.
  3. 런타임에 객체 간의 의존 관계를 동적으로 변경해야 할 때:
    • 예: 구독 기반 애플리케이션.

실제 응용 사례

  1. 이벤트 시스템:
    • DOM 이벤트 리스너(브라우저의 addEventListener).
  2. 데이터 동기화:
    • 모델과 뷰 간 데이터 동기화(MVC 패턴).
  3. 알림 시스템:
    • 이메일, 푸시 알림, SMS 등 여러 채널로 메시지를 전송.
  4. 퍼블리셔-서브스크라이버 시스템:
    • Kafka, RabbitMQ 같은 메시지 큐 시스템.

'디자인패턴' 카테고리의 다른 글

디자인패턴 - 이터레이터 패턴  (0) 2024.12.17
프록시패턴 (Proxy Pattern)  (0) 2024.12.15
디자인패턴 - 전략패턴  (2) 2024.12.14
디자인패턴 - 팩토리 패턴  (0) 2024.12.12
디자인 패턴 - 싱글톤 패턴  (0) 2024.12.12