🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

Observer Pattern 실무 활용 가이드 - 슬라이드 1/13
A

AI Generated

2025. 11. 4. · 49 Views

Observer Pattern 실무 활용 가이드

Observer Pattern의 고급 활용 방법을 실무 중심으로 알아봅니다. 이벤트 기반 아키텍처, 메모리 관리, 성능 최적화까지 실전에서 바로 사용할 수 있는 패턴을 다룹니다.


카테고리:TypeScript
언어:TypeScript
메인 태그:#TypeScript
서브 태그:
#ObserverPattern#DesignPatterns#EventDriven#Architecture

들어가며

이 글에서는 Observer Pattern 실무 활용 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.

목차

  1. 기본_Observer_구현
  2. 타입_안전한_이벤트_시스템
  3. 자동_구독_해제_패턴
  4. 조건부_알림_최적화
  5. 우선순위_기반_알림
  6. 비동기_Observer_처리
  7. 에러_핸들링_패턴
  8. 선택적_구독_필터링
  9. Once_구독_패턴
  10. WeakMap_기반_메모리_관리
  11. Debounced_알림_패턴
  12. 이벤트_버스_패턴

1. 기본 Observer 구현

개요

Observer Pattern의 기본 구조를 TypeScript로 구현합니다. Subject와 Observer 인터페이스를 정의하여 느슨한 결합을 만듭니다.

코드 예제

interface Observer {
  update(data: any): void;
}

class Subject {
  private observers: Observer[] = [];

  attach(observer: Observer) {
    this.observers.push(observer);
  }

  notify(data: any) {
    this.observers.forEach(o => o.update(data));
  }
}

설명

Subject는 observers 배열로 구독자를 관리하고, notify로 모든 구독자에게 데이터를 전파합니다.


2. 타입 안전한 이벤트 시스템

개요

제네릭을 활용하여 타입 안전성을 보장하는 이벤트 시스템을 구현합니다.

코드 예제

class TypedEventEmitter<T> {
  private listeners: ((data: T) => void)[] = [];

  subscribe(callback: (data: T) => void) {
    this.listeners.push(callback);
    return () => this.unsubscribe(callback);
  }

  emit(data: T) {
    this.listeners.forEach(cb => cb(data));
  }
}

설명

제네릭 T로 이벤트 데이터 타입을 지정하여, 컴파일 타임에 타입 오류를 잡을 수 있습니다.


3. 자동 구독 해제 패턴

개요

메모리 누수를 방지하기 위해 구독 해제 함수를 반환하는 패턴입니다.

코드 예제

class Store<T> {
  private state: T;
  private listeners = new Set<(state: T) => void>();

  subscribe(listener: (state: T) => void) {
    this.listeners.add(listener);
    listener(this.state);
    return () => this.listeners.delete(listener);
  }
}

설명

subscribe가 unsubscribe 함수를 반환하여, 컴포넌트 언마운트 시 쉽게 정리할 수 있습니다.


4. 조건부 알림 최적화

개요

모든 변경사항을 알리지 않고, 실제 값이 변경될 때만 notify하여 성능을 최적화합니다.

코드 예제

class OptimizedStore<T> {
  private state: T;
  private listeners = new Set<(state: T) => void>();

  setState(newState: T) {
    if (this.state !== newState) {
      this.state = newState;
      this.listeners.forEach(fn => fn(newState));
    }
  }
}

설명

얕은 비교로 상태 변경을 체크하여 불필요한 렌더링이나 연산을 방지합니다.


5. 우선순위 기반 알림

개요

옵저버에게 우선순위를 부여하여 특정 순서로 알림을 받을 수 있게 합니다.

코드 예제

class PrioritySubject {
  private observers: Map<number, Set<Function>> = new Map();

  subscribe(fn: Function, priority: number = 0) {
    if (!this.observers.has(priority)) {
      this.observers.set(priority, new Set());
    }
    this.observers.get(priority)!.add(fn);
  }

  notify(data: any) {
    [...this.observers.keys()].sort((a, b) => b - a)
      .forEach(p => this.observers.get(p)!.forEach(fn => fn(data)));
  }
}

설명

우선순위가 높은 옵저버부터 실행되어, 중요한 로직을 먼저 처리할 수 있습니다.


6. 비동기 Observer 처리

개요

비동기 작업을 처리하는 옵저버를 위해 Promise 기반으로 구현합니다.

코드 예제

class AsyncSubject {
  private observers: ((data: any) => Promise<void>)[] = [];

  subscribe(fn: (data: any) => Promise<void>) {
    this.observers.push(fn);
  }

  async notify(data: any) {
    await Promise.all(
      this.observers.map(fn => fn(data))
    );
  }
}

설명

Promise.all로 모든 비동기 옵저버를 병렬로 실행하고, 모두 완료될 때까지 대기합니다.


7. 에러 핸들링 패턴

개요

하나의 옵저버 에러가 전체 알림 체인을 중단하지 않도록 에러를 격리합니다.

코드 예제

class SafeSubject {
  private observers: Function[] = [];

  notify(data: any) {
    this.observers.forEach(fn => {
      try {
        fn(data);
      } catch (error) {
        console.error('Observer error:', error);
      }
    });
  }
}

설명

try-catch로 각 옵저버를 감싸서, 한 옵저버의 실패가 다른 옵저버에 영향을 주지 않습니다.


8. 선택적 구독 필터링

개요

특정 조건을 만족하는 이벤트만 받도록 필터링 기능을 추가합니다.

코드 예제

class FilterableSubject<T> {
  private observers: Map<Function, (data: T) => boolean> = new Map();

  subscribe(fn: Function, filter?: (data: T) => boolean) {
    this.observers.set(fn, filter || (() => true));
  }

  notify(data: T) {
    this.observers.forEach((filter, fn) => {
      if (filter(data)) fn(data);
    });
  }
}

설명

filter 함수로 조건을 지정하여, 관심 있는 이벤트만 처리할 수 있어 효율적입니다.


9. Once 구독 패턴

개요

한 번만 실행되고 자동으로 구독 해제되는 일회성 옵저버를 구현합니다.

코드 예제

class EventEmitter {
  private listeners = new Map<string, Set<Function>>();

  once(event: string, fn: Function) {
    const wrapper = (data: any) => {
      fn(data);
      this.listeners.get(event)?.delete(wrapper);
    };
    this.on(event, wrapper);
  }
}

설명

wrapper 함수가 실행 후 스스로를 제거하여, 이벤트를 한 번만 처리하고 메모리를 정리합니다.


10. WeakMap 기반 메모리 관리

개요

WeakMap을 사용하여 객체가 가비지 컬렉션될 때 자동으로 구독이 해제되도록 합니다.

코드 예제

class WeakObserver {
  private observers = new WeakMap<object, Function>();

  subscribe(target: object, fn: Function) {
    this.observers.set(target, fn);
  }

  notify(data: any) {
    // WeakMap은 순회 불가, 특정 target으로 접근
  }
}

설명

WeakMap은 키 객체가 더 이상 참조되지 않으면 자동으로 제거되어 메모리 누수를 방지합니다.


11. Debounced 알림 패턴

개요

짧은 시간 내 여러 변경사항을 하나로 묶어서 알림 횟수를 줄입니다.

코드 예제

class DebouncedSubject {
  private observers: Function[] = [];
  private timeout: NodeJS.Timeout | null = null;

  notify(data: any, delay = 300) {
    if (this.timeout) clearTimeout(this.timeout);
    this.timeout = setTimeout(() => {
      this.observers.forEach(fn => fn(data));
    }, delay);
  }
}

설명

delay 시간 내 마지막 호출만 실행되어, 빈번한 상태 변경 시 성능을 크게 향상시킵니다.


12. 이벤트 버스 패턴

개요

전역 이벤트 버스로 컴포넌트 간 통신을 구현합니다. 여러 이벤트 타입을 관리합니다.

코드 예제

class EventBus {
  private events = new Map<string, Set<Function>>();

  on(event: string, fn: Function) {
    if (!this.events.has(event)) {
      this.events.set(event, new Set());
    }
    this.events.get(event)!.add(fn);
  }

  emit(event: string, data: any) {
    this.events.get(event)?.forEach(fn => fn(data));
  }
}

설명

이벤트 이름으로 구분하여 여러 타입의 메시지를 관리하고, 컴포넌트 간 느슨한 결합을 유지합니다.


마치며

이번 글에서는 Observer Pattern 실무 활용 가이드에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.

관련 태그

#TypeScript #ObserverPattern #DesignPatterns #EventDriven #Architecture

#TypeScript#ObserverPattern#DesignPatterns#EventDriven#Architecture

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.
이전4/4
다음