옵저버 패턴 (Observer Pattern)
1. 정의
옵저버 패턴(Observer Pattern)은 객체의 상태 변화를 다른 객체들에게 자동으로 알리고, 그에 따른 대응을 할 수 있도록 하는 디자인 패턴입니다. 객체 간의 일대다(one-to-many) 의존 관계를 정의하여, 한 객체의 상태가 변경되면 관련된 다른 객체들에게 알림을 전달하는 구조입니다.
이 패턴에서 주체 객체(Subject)는 상태가 변할 때 옵저버 객체(Observer)들에게 알림을 보내며, 옵저버들은 주체 객체의 상태를 감지하고 적절히 대응합니다. 이를 통해 객체 간의 결합도를 낮추고, 동적이고 유연한 상호작용이 가능합니다.
2. 목적
- 상태 변화에 따른 자동 업데이트: 주체 객체의 상태 변화가 있을 때 관련된 옵저버들이 자동으로 상태 변화를 인식하고 대응할 수 있도록 합니다.
- 객체 간 결합도 감소: 주체 객체와 옵저버 객체가 직접적으로 서로를 참조하지 않고, 느슨한 결합(loose coupling)을 유지할 수 있습니다. 옵저버는 주체 객체의 상태 변화에만 관심을 가지며, 주체 객체는 옵저버의 구체적인 구현에 의존하지 않습니다.
- 확장성: 새로운 옵저버를 추가하거나 제거하는 것이 용이하며, 주체 객체의 코드를 수정하지 않고도 옵저버가 상태 변화를 감지할 수 있습니다.
3. 사용 예시
옵저버 패턴은 다음과 같은 경우에 유용합니다:
- GUI에서 버튼 클릭 이벤트나 상태 변화 등을 처리할 때
- 게시판이나 뉴스 구독 시스템과 같이 여러 클라이언트가 데이터를 구독하고, 데이터가 변경될 때마다 알림을 받는 경우
- 주식 가격, 날씨 정보와 같은 실시간 데이터가 변경될 때 다수의 시스템에 알림을 보내는 경우
4. 구현 방법
옵저버 패턴에서는 보통 두 가지 주요 역할이 있습니다:
- 주체 객체 (Subject): 상태를 관리하고, 옵저버를 등록하거나 해제하며, 상태가 변경될 때 옵저버에게 알립니다.
- 옵저버 객체 (Observer): 주체 객체의 상태 변화를 감지하고 적절하게 대응하는 객체입니다.
자바에서 옵저버 패턴을 구현할 때는, Observer
인터페이스와 Subject
를 구현하는 클래스를 통해 옵저버가 주체 객체의 상태를 감시합니다.
// 1. 옵저버 인터페이스
interface Observer {
void update(String message);
}
// 2. 주체 객체 (Subject)
interface Subject {
void registerObserver(Observer o); // 옵저버 등록
void removeObserver(Observer o); // 옵저버 해제
void notifyObservers(); // 옵저버들에게 알림
}
// 3. 주체 객체의 구체적인 구현 클래스
class NewsPublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update(latestNews); // 옵저버들에게 최신 뉴스 전달
}
}
// 뉴스 업데이트 메서드
public void setLatestNews(String news) {
this.latestNews = news;
notifyObservers(); // 상태 변경 시 옵저버들에게 알림
}
}
// 4. 옵저버의 구체적인 구현 클래스
class NewsSubscriber implements Observer {
private String name;
public NewsSubscriber(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received news update: " + message);
}
}
// 5. 클라이언트 코드
public class ObserverPatternDemo {
public static void main(String[] args) {
NewsPublisher publisher = new NewsPublisher();
// 옵저버(구독자) 생성
Observer subscriber1 = new NewsSubscriber("Alice");
Observer subscriber2 = new NewsSubscriber("Bob");
// 옵저버 등록
publisher.registerObserver(subscriber1);
publisher.registerObserver(subscriber2);
// 뉴스 업데이트 시 옵저버들에게 알림
publisher.setLatestNews("Breaking News: Observer Pattern in Java!");
// 한 명의 구독자를 제거 후 뉴스 업데이트
publisher.removeObserver(subscriber1);
publisher.setLatestNews("More News: Alice unsubscribed.");
}
}
5. 동작 설명
- Subject 인터페이스는 옵저버를 등록(
registerObserver
), 해제(removeObserver
), 알림(notifyObservers
)하는 메서드를 정의합니다. - NewsPublisher 클래스는 주체 객체의 구체적인 구현체로, 옵저버들의 목록을 관리하고, 뉴스가 업데이트될 때 모든 옵저버에게 알림을 보냅니다.
- Observer 인터페이스는
update()
메서드를 정의하여 주체 객체로부터 알림을 받을 때 호출됩니다. - NewsSubscriber는 옵저버의 구체적인 구현체로, 새로운 뉴스 알림을 받으면 이를 처리합니다.
6. 장점
- 객체 간의 느슨한 결합: 주체 객체와 옵저버 객체는 서로 직접적인 참조가 없고 인터페이스를 통해 상호작용하므로, 객체 간의 결합도가 낮아집니다.
- 확장성: 새로운 옵저버를 쉽게 추가할 수 있으며, 주체 객체는 이를 신경 쓸 필요가 없습니다. 주체 객체의 코드 변경 없이도 기능을 확장할 수 있습니다.
- 자동 상태 전파: 주체 객체의 상태 변화가 있을 때 옵저버들이 자동으로 업데이트를 받을 수 있어, 상태 변화를 수동으로 전달할 필요가 없습니다.
7. 단점
- 성능 문제: 옵저버가 많아질수록 주체 객체가 상태 변화를 통보하는 데 시간이 걸릴 수 있습니다. 특히, 옵저버가 복잡한 작업을 수행할 경우 성능 저하가 발생할 수 있습니다.
- 의존성 문제: 옵저버들은 주체 객체의 상태 변화에 의존하게 되므로, 주체 객체가 자주 상태 변화를 일으킬 경우 옵저버들이 너무 자주 알림을 받을 수 있어 불필요한 업데이트가 발생할 수 있습니다.
- 순환 참조 위험: 옵저버 패턴을 구현할 때, 잘못된 설계로 인해 주체 객체와 옵저버 사이에 순환 참조가 발생하면 무한 루프에 빠질 수 있습니다.
8. 옵저버 패턴이 유용한 경우
- 이벤트 기반 시스템: GUI 응용 프로그램에서 버튼 클릭, 마우스 이벤트 등 다양한 사용자 입력에 대한 응답이 필요할 때.
- 실시간 데이터 시스템: 주식 가격, 날씨 정보와 같이 실시간으로 데이터가 변경될 때 이를 여러 사용자에게 동적으로 알리는 시스템.
- 게시판 및 알림 시스템: 게시판의 새 글 알림, 이메일 알림, SMS 알림 등 여러 채널로 업데이트를 자동으로 보내야 할 때 유용합니다.
9. 자바의 내장 옵저버 패턴
자바는 java.util.Observable
클래스와 java.util.Observer
인터페이스를 통해 옵저버 패턴을 지원합니다. 하지만 Observable
클래스는 구조가 유연하지 않고 상속을 요구하므로, 실무에서는 보통 위에서 설명한 방식처럼 커스텀 구현을 선호하는 경우가 많습니다.
옵저버 패턴은 이벤트 기반의 시스템이나, 상태 변화가 자주 발생하는 상황에서 여러 객체들이 그 변화를 감지하고 대응할 수 있는 상황에서 매우 유용한 패턴입니다.
'언어 > Java' 카테고리의 다른 글
[ Java ] Template Method Pattern - 템플릿 메서드 패턴 알아보기 (1) | 2024.10.03 |
---|---|
[ Java ] Strategy Pattern - 전략 패턴 알아보기 (0) | 2024.10.03 |
[ Java ] Proxy Pattern - 프록시 패턴 알아보기 (1) | 2024.10.03 |
[ Java ] Decoration Pattern - 데코레이션 패턴 알아보기 (0) | 2024.10.03 |
[ Java ] Builder Pattern - 빌더 패턴 알아보기 (1) | 2024.10.03 |