본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 4. · 50 Views
Observer Pattern 실무 활용 가이드
Observer Pattern의 고급 활용 방법을 실무 중심으로 알아봅니다. 이벤트 기반 아키텍처, 메모리 관리, 성능 최적화까지 실전에서 바로 사용할 수 있는 패턴을 다룹니다.
들어가며
이 글에서는 Observer Pattern 실무 활용 가이드에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- 기본_Observer_구현
- 타입_안전한_이벤트_시스템
- 자동_구독_해제_패턴
- 조건부_알림_최적화
- 우선순위_기반_알림
- 비동기_Observer_처리
- 에러_핸들링_패턴
- 선택적_구독_필터링
- Once_구독_패턴
- WeakMap_기반_메모리_관리
- Debounced_알림_패턴
- 이벤트_버스_패턴
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
댓글 (0)
함께 보면 좋은 카드 뉴스
UX와 협업 패턴 완벽 가이드
AI 에이전트와 사용자 간의 효과적인 협업을 위한 UX 패턴을 다룹니다. 프롬프트 핸드오프부터 인터럽트 처리까지, 현대적인 에이전트 시스템 설계의 핵심을 배웁니다.
자가 치유 및 재시도 패턴 완벽 가이드
AI 에이전트와 분산 시스템에서 필수적인 자가 치유 패턴을 다룹니다. 에러 감지부터 서킷 브레이커까지, 시스템을 스스로 복구하는 탄력적인 코드 작성법을 배워봅니다.
Feedback Loops 컴파일러와 CI/CD 완벽 가이드
컴파일러 피드백 루프부터 CI/CD 파이프라인, 테스트 자동화, 자가 치유 빌드까지 현대 개발 워크플로우의 핵심을 다룹니다. 초급 개발자도 쉽게 이해할 수 있도록 실무 예제와 함께 설명합니다.
실전 MCP 통합 프로젝트 완벽 가이드
Model Context Protocol을 활용한 실전 통합 프로젝트를 처음부터 끝까지 구축하는 방법을 다룹니다. 아키텍처 설계부터 멀티 서버 통합, 모니터링, 배포까지 운영 레벨의 MCP 시스템을 구축하는 노하우를 담았습니다.
MCP 동적 도구 업데이트 완벽 가이드
AI 에이전트의 도구를 런타임에 동적으로 로딩하고 관리하는 방법을 알아봅니다. 플러그인 시스템 설계부터 핫 리로딩, 보안까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.