현재 취업준비중에 면접을 보면서 옵저버 패턴에 대해 설명하라는 질문을 받았다.
결국에 추측으로 답을 했지만, 정확한 답은 아니였고 이의 대한 복기겸 나의 성장을 위해 옵저버 패턴에 대해 다시 작성해본다.
옵저버 패턴이란?
옵저버 패턴은 디자인 패턴중 행위 패턴에 속하며, 한 객체의 상태가 변화하면 그 객체에 의존하는 모든 객체들에 알림을 보내고 내용을 갱신하는 1:N 의존성을 가진 특징을 가지고 있다.
이렇게 정의하면 될 것 같다.
쉽게 보면 사진과 같은 식의 구조로 이루어진다.

옵저버 패턴은 언제 사용하는가?
옵저버 패턴은 한 객체의 상태가 변경되었을 때, 그 객체에 등록된 다수의 객체들에게 직접 변경 사항을 통지하고 싶을 때 사용한다. 이때 주체(Subject)는 관찰자(Observer)가 구체적으로 어떤 클래스인지 몰라도 되며, 단지 알림을 받을 수 있는 인터페이스가 구현되어 있다는 사실만 알고 소통한다.
옵저버 패턴 예시 (구독 시스템)
유튜브 구독 시스템이 가장 대표적인 예시이다.
- Subject (주체): 유튜버 1명
- Observer (관찰자): 구독자 100만 명
유튜버가 영상을 업로드(상태 변경)하면, 내부에 관리하고 있던 구독자 리스트를 하나씩 참조하여 직접 '업데이트' 신호를 보낸다. 이를 통해 새로운 영상이 올라왔음을 구독자들에게 1:N으로 전파한다.
요약
- 옵저버 패턴은 한 객체(Subject)의 상태 변화를 다수의 객체(Observer)에게 자동으로 1 : N 전파가 필요할 경우에 사용한다.
- 객체 간의 의존성을 낮추고 싶을 때 즉 데이터를 주는 쪽(Subject)이 데이터를 받는 쪽(Observer)의 코드를 전혀 몰라도 통신이 가능하게 하고 싶을 때 사용한다.
옵저버 패턴의 한계점
옵저버 패턴은 초고속 실시간 동기화/과부하, 그리고 리스트 관리의 문제가 있다.
콘서트 티켓팅을 예시로 들수 있다.
- 상황: 좌석 1개가 예매 완료됨(Subject 변경) ↔ 대기자 1만 명(Observers)
- 문제점: 누군가 결제할 때마다 10만 명의 화면을 실시간으로 갱신하려 하면, 알림을 보내다 서버가 다운되고, 그리고 계속적으로 많은 Observer의 리스트를 관리해된다.
- 해결책
- 따라서 이런 경우에는 옵저버 패턴의 자동 통지(Push) 대신, 사용자가 클릭했을 때 확인하는 요청-응답(Pull/Request) 방식이나 폴링(Polling) 방식을 사용하여 부하를 줄인다.
- 리스트 관리의 경우 pub - sub 방식으로 변경한다.
옵저버 패턴과 발행-구독 패턴(Publisher-Subscriber Pattern)의 차이
옵저버 패턴을 조사하다보니 발행-구독(Publisher-Subscriber Pattern) 패턴도 존재하는데, 둘을 유사하지만 차이점이 존재한다.
옵저버 패턴과 발행-구독 패턴의 가장 큰 차이는 중개자(Event Broker)의 존재 여부이다.

옵저버 패턴은 주체가 관찰자를 인지하고 직접 통지하는 동기적 방식으로, 주로 단일 애플리케이션 내부의 상태 관리에 사용된다. 반면, 발행-구독 패턴은 발행자와 구독자 사이에 '브로커'가 존재하여 서로의 존재를 모르는 완전한 비동기적 결합을 이룬다.
이 덕분에 대규모 분산 시스템이나 메시지 큐(Kafka 등) 환경에서 시스템 간의 결합도를 낮추고 부하를 조절하는 데 더 적합하다.
옵저버 패턴 코드 작성 (Java)
import java.util.ArrayList;
import java.util.List;
// 1. Observer 인터페이스 (구독자 공통 규약)
interface Observer {
void update(String videoTitle);
}
// 2. Subject 인터페이스 (유튜버 공통 규약)
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 3. ConcreteSubject (실제 유튜버)
class Youtuber implements Subject {
private List<Observer> subscribers = new ArrayList<>(); // 구독자 명단
private String newVideo; // 상태 (새 영상 제목)
@Override
public void registerObserver(Observer o) {
subscribers.add(o);
}
@Override
public void removeObserver(Observer o) {
subscribers.remove(o);
}
@Override
public void notifyObservers() {
// 모든 구독자에게 알림 발송 (update 호출)
for (Observer subscriber : subscribers) {
subscriber.update(newVideo);
}
}
// 영상 업로드 (상태 변경 -> 알림)
public void uploadVideo(String title) {
System.out.println(">>> 유튜버: 새 영상 [" + title + "] 업로드!");
this.newVideo = title;
notifyObservers();
}
}
// 4. ConcreteObserver (실제 구독자)
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String videoTitle) {
System.out.println("알림 수신(" + name + "): [" + videoTitle + "] 영상이 올라왔어요! 보러 갑니다.");
}
}
// 실행부
public class Main {
public static void main(String[] args) {
Youtuber myChannel = new Youtuber();
Subscriber user1 = new Subscriber("철수");
Subscriber user2 = new Subscriber("영희");
// 구독 신청 (Register)
myChannel.registerObserver(user1);
myChannel.registerObserver(user2);
// 영상 업로드 (상태 변경 -> 자동 알림)
myChannel.uploadVideo("옵저버 패턴 완전 정복");
}
}
옵저버 패턴에 대한 나의 생각
옵저버 패턴을 보고 공부하고 느낀점은 “하나의 이벤트로 다수의 동작을 트리거하는 로직" 이라고만 막연하게 생각했던 개념이, 옵저버 패턴이라는 정형화된 디자인 패턴으로 정의되어 있다는 점을 명확히 알게 되었다.
그리고 옵저버 패턴과 발행-구독(Publisher-Subscriber Pattern) 패턴의 서로 다른점에 대해 확실히 알아야된다는 점이다.
- 옵저버 패턴: 객체 간 직접 연결(동기), 강한 결합
- Pub-Sub 패턴: 중개자(Broker)를 통한 간접 연결(비동기), 느슨한 결합
이 부분을 정확하게 명확하게 알아야된다
또한, 옵저버 패턴의 단점, 대규모 트래픽 상황에서 옵저버 패턴이 가질 수 있는 동기화 부하 및 성능 이슈를 인지하고, 상황에 따라 Polling이나 Pub-Sub 같은 적절한 해결책을 적절하게 선택해 문제를 해결해야되는 부분을 인지 해야된다는점.
제일 중요한 나중에 pub-sub 패턴을 구현해놓고 옵저버 패턴이라고 말하는 불상사는 없어야겠다.
참고
https://refactoring.guru/ko/design-patterns/observer
https://www.hanbit.co.kr/channel/view.html?cmscode=CMS8616098823