옵저버 observer 패턴 - 자바스크립트 예제
요약
옵저버 observer 패턴을 타입스크립트 코드와 함께 알아봅니다.
옵저버 패턴 요약
패턴 종류 | 핵심 키워드 |
---|---|
옵저버 (Observer) | 한 객체 바뀌면 의존하는 다른 객체에 연락 가고 자동으로 갱신, 일대다, 발행(Publish)/수신(Subscribe) |

옵저버 (Observer) 패턴
옵저버 패턴은 한 객체의 상태가 변하면, 그 객체에 의존하는 다른 객체들에게 자동으로 알림(notification)을 보내고 상태를 갱신할 수 있게 하는 일대다(one-to-many) 의존성 관계를 정의하는 패턴입니다. 상태를 가진 객체를 Subject
(주제), 상태의 변화를 통지받는 객체들을 Observer
(관찰자)라고 합니다.
현실 세계의 예로 '유튜브 채널 구독' 을 들 수 있습니다. 유튜버(Subject
)가 새로운 영상을 올리면, 그 채널을 구독(register
)한 모든 구독자(Observer
)들에게 자동으로 알림이 갑니다. 구독을 취소(unregister
)하면 더 이상 알림을 받지 않습니다. 옵저버 패턴은 이처럼 느슨하게 연결된(loosely coupled) 객체들 간의 자동화된 소통 방식을 구현할 때 매우 유용합니다.
기본 구조
- Subject: 관찰 대상이 되는 객체입니다. 내부에 옵저버 목록을 가지고 있으며, 옵저버를 등록(
register
)하고 제거(unregister
)하는 메서드를 제공합니다. 상태가 변경되면notify()
메서드를 호출하여 모든 옵저버에게 변경 사실을 알립니다. - Observer:
Subject
의 상태 변화를 통지받는 객체들이 구현해야 할 인터페이스입니다. 보통update()
와 같은 메서드를 정의하며,Subject
로부터 알림이 오면 이 메서드가 호출됩니다. - ConcreteSubject:
Subject
인터페이스를 구현한 구체적인 클래스입니다. 상태를 저장하고, 상태가 변경될 때 옵저버들에게 알리는 역할을 합니다. - ConcreteObserver:
Observer
인터페이스를 구현한 구체적인 클래스입니다.update()
메서드가 호출되면 특정 동작을 수행합니다.
예시: 뉴스레터 구독 시스템
새로운 기사가 발행될 때마다 구독자들에게 이메일로 알려주는 뉴스레터 시스템을 만들어 보겠습니다.
먼저, 모든 옵저버(구독자)가 구현할 Observer
인터페이스를 정의합니다.
// Observer: 구독자 인터페이스
class Subscriber {
update(article) {
throw new Error("update() 메서드는 반드시 구현되어야 합니다.");
}
}
다음으로, 관찰 대상인 NewsPublisher
(뉴스 발행사)를 Subject
로 만듭니다.
// Subject: 뉴스 발행사
class NewsPublisher {
constructor() {
this.subscribers = []; // 옵저버(구독자) 목록
this.latestArticle = null;
}
// 옵저버 등록
register(subscriber) {
this.subscribers.push(subscriber);
console.log(`${subscriber.name}님이 구독을 시작했습니다.`);
}
// 옵저버 제거
unregister(subscriber) {
this.subscribers = this.subscribers.filter((sub) => sub !== subscriber);
console.log(`${subscriber.name}님이 구독을 취소했습니다.`);
}
// 모든 옵저버에게 알림
notify() {
console.log("\n--- 새로운 기사 발행! 모든 구독자에게 알림 전송 ---");
this.subscribers.forEach((subscriber) => {
subscriber.update(this.latestArticle);
});
}
// 새로운 기사 발행 (상태 변경)
publishNewArticle(article) {
this.latestArticle = article;
this.notify();
}
}
이제 구체적인 구독자, EmailSubscriber
를 ConcreteObserver
로 구현합니다.
// ConcreteObserver: 이메일 구독자
class EmailSubscriber extends Subscriber {
constructor(name) {
super();
this.name = name;
}
update(article) {
console.log(
`[${this.name}님에게 이메일 전송] 새로운 기사: "${article.title}"`
);
}
}
// 클라이언트 코드
const publisher = new NewsPublisher();
const sub1 = new EmailSubscriber("김재현");
const sub2 = new EmailSubscriber("이영희");
publisher.register(sub1); // 김재현님 구독 시작
publisher.register(sub2); // 이영희님 구독 시작
publisher.publishNewArticle({
title: "AI, 인간의 일자리를 대체할까?",
content: "...",
});
// 출력:
// --- 새로운 기사 발행! 모든 구독자에게 알림 전송 ---
// [김재현님에게 이메일 전송] 새로운 기사: "AI, 인간의 일자리를 대체할까?"
// [이영희님에게 이메일 전송] 새로운 기사: "AI, 인간의 일자리를 대체할까?"
publisher.unregister(sub2); // 이영희님 구독 취소
publisher.publishNewArticle({
title: "2025년 기술 트렌드 전망",
content: "...",
});
// 출력:
// --- 새로운 기사 발행! 모든 구독자에게 알림 전송 ---
// [김재현님에게 이메일 전송] 새로운 기사: "2025년 기술 트렌드 전망"
NewsPublisher
는 어떤 종류의 구독자가 있는지, 구독자가 이메일을 받는지 앱 푸시를 받는지 전혀 알 필요가 없습니다. 그저 subscribers
목록에 있는 각 객체의 update()
메서드를 호출할 뿐입니다. 만약 '앱 푸시 알림' 기능이 필요하다면, AppPushSubscriber
라는 새로운 옵저버 클래스를 만들어 등록하기만 하면 됩니다.
이처럼 옵저버 패턴은 Subject
와 Observer
간의 결합도를 낮춰, 시스템을 유연하고 확장 가능하게 만듭니다.
옵저버 패턴 중요 키워드
- 일대다(one-to-many) 의존 관계를 정의합니다.
- 느슨한 결합(Loose Coupling): Subject는 Observer의 구체적인 클래스를 몰라도 됩니다.
- 상태 변경 시 자동으로 의존 객체에 전파(broadcast)됩니다.
- 이벤트 기반 시스템, MVC(Model-View-Controller) 아키텍처 등에서 널리 사용됩니다.
- 발행/구독(Publish/Subscribe) 모델이라고도 불립니다.
정처기 실기 기출 문제
기출 | |
문제 | 한 객체의 상태가 변화하면 객체에 상속되어 있는 다른 객체들에게 변화된 상태를 전달해주는 패턴을 보기에서 고르시오 |
보기 | |
답변 | |
정답 | 정답 보기 |
기출 | |
문제 | 일대다 관계를 가지고, 분산된 시스템 간에 이벤트 발행(Publish) 및 수신(Subscribe)이 필요할 때 이용하는 패턴을 보기에서 고르시오 |
보기 | |
답변 | |
정답 | 정답 보기 |