노트

옵저버 패턴

Observer

설계#pattern · 연결된 개념 9개

쉽게 말하면

옵저버 패턴은 유튜브 채널 구독과 같아요. 채널이 새 영상을 올리면 구독자에게 알림이 가고, 채널은 구독자가 누구인지 하나하나 신경 쓰지 않아도 돼요.

비유가 깨지는 곳 구독 해제를 잊으면 이미 사라진 화면에도 알림이 계속 가서 메모리 누수가 생겨요. 알림이 또 다른 알림을 부르는 연쇄가 생기면 흐름을 따라가기도 어려워요.

한 객체(발행자, Publisher)의 상태가 바뀌면 그것을 구독한 객체(구독자, Subscriber)들에게 자동으로 알리는 패턴. 발행자는 구독자가 누구인지 구체적으로 몰라도 된다.

function createStore<T>(initial: T) {
  let state = initial
  const listeners = new Set<(s: T) => void>()
  return {
    get: () => state,
    set(next: T) { state = next; listeners.forEach(l => l(state)) },
    subscribe(l: (s: T) => void) { listeners.add(l); return () => listeners.delete(l) },
  }
}
  • 이벤트 리스너, UI 데이터 바인딩, 상태 관리 라이브러리의 구독이 모두 이 구조다. 외부 스토어를 React에 연결하는 useSyncExternalStore가 정확히 subscribe와 get을 요구한다
  • DOM 이벤트의 addEventListener도 옵저버다(이벤트 버블링·캡처링과 위임)
  • 엄밀히는 발행자가 구독자 목록을 직접 들고 있으면 옵저버, 중간에 메시지 브로커(Message Broker)를 두고 서로를 전혀 모르면 발행-구독(Publish-Subscribe)이라 구분하기도 한다. 시스템 사이의 발행-구독은 Kafka 같은 메시지 큐가 맡는다

주의할 점

  • 구독 해제를 잊으면 메모리 누수(Memory Leak)와 이미 사라진 화면의 갱신이 생긴다. 위 예처럼 subscribe가 해제 함수를 돌려주게 하고 정리 시점에 부른다(Effect 정리 함수)
  • 알림이 또 다른 알림을 부르는 연쇄·순환이 생기면 흐름을 추적하기 어렵다
  • 알림 순서에 기대는 코드를 만들지 않는다

행동 패턴 전체는 행동 패턴.

출처: Observer — Refactoring.Guru

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 상태 패턴

    객체의 행동이 현재 상태에 따라 달라질 때, 상태마다 별도 객체를 두고 현재 상태 객체에 행동을 맡기는 패턴. 상태별 조건문이 메서드마다 반복되는 문제를 푼다.

  • 트랜잭셔널 아웃박스 패턴

    DB 변경과 이벤트 발행을 안전하게 함께 처리하는 패턴이다. 실제 데이터 변경과 "이 이벤트를 내보내라"는 기록(outbox 행)을 같은 DB 트랜잭션에 넣고, 별도 워커가 outbox를 읽어 메시지 브로커로 보낸다.

  • 커맨드 패턴

    요청이나 작업을 실행 가능한 객체로 포장하는 패턴. 작업을 값처럼 저장·전달·대기열에 넣을 수 있게 되고, 되돌리기 같은 부가 연산을 붙일 수 있다.

  • 전략 패턴

    같은 목적을 가진 여러 알고리즘을 각각 별도 객체(또는 함수)로 빼고, 실행할 때 그중 하나를 골라 끼우는 패턴. 호출하는 쪽은 공통 인터페이스만 안다.

  • 어댑터 패턴

    쓸 수 있는 객체가 있는데 인터페이스가 맞지 않을 때, 중간에서 호출을 받아 실제 객체가 알아듣는 형태로 바꿔 주는 패턴. 전원 플러그 변환기와 같다.

보기 옵션