[Design Pattern] 옵저버 패턴(Observer Pattern)

하리보·2025년 3월 19일
post-thumbnail

옵저버 패턴(Observer Pattern)

1. 옵저버 패턴이란?

옵저버 패턴(Observer Pattern)은 한 객체의 상태가 변경될 때, 이를 의존하는 객체들에게 자동으로 알림을 보내는 패턴입니다. 발행(Publisher) - 구독(Subscriber) 모델로도 알려져 있으며, 한 객체(subject)의 상태 변화가 여러 객체(observer)에게 영향을 미쳐야 하는 경우 유용합니다.

2. 왜 옵저버 패턴을 사용할까요?

문제 상황

일반적으로 한 객체의 상태가 변할 때, 여러 객체에서 이를 감지해야 한다면 직접적으로 여러 객체를 참조해야 합니다. 하지만 이렇게 하면 결합도가 높아지고 유지보수가 어려워지는 문제가 발생합니다.

해결 방법

옵저버 패턴을 적용하면 느슨한 결합(Loose Coupling) 을 유지하면서도 객체 간의 관계를 효과적으로 관리할 수 있습니다. 즉, Subject는 Observer가 어떤 객체인지 알 필요가 없으며, 단순히 Observer 인터페이스를 통해 상태 변경을 알리기만 하면 됩니다.


3. 옵저버 패턴의 구조

주요 구성 요소

  1. Subject (주제, 발행자)
    • 옵저버들을 등록/제거하는 메서드를 제공합니다.
    • 상태가 변경되면 등록된 옵저버들에게 알립니다.
  2. Observer (옵저버, 구독자)
    • Subject의 상태가 변경될 때, 알림을 받고 적절한 동작을 수행합니다.
  3. ConcreteSubject (구체적인 주제)
    • Subject의 구체적인 구현체로, 상태를 저장하고 변경 사항을 옵저버들에게 알립니다.
  4. ConcreteObserver (구체적인 옵저버)
    • Subject로부터 상태 변경을 알림받아 적절한 행동을 수행합니다.

UML 다이어그램 (텍스트 표현)

+-------------------+       +------------------+
|     Subject      |<------|     Observer     |
+-------------------+       +------------------+
| + register()     |       | + update()       |
| + remove()       |       +------------------+
| + notify()       |
+-------------------+
        |                    
        v                    
+----------------------+      +----------------------+
|  ConcreteSubject    |      |  ConcreteObserver   |
+----------------------+      +----------------------+
| - state             |      | - subject            |
| + getState()        |      | + update()           |
| + setState()        |      +----------------------+
+----------------------+

4. Java로 구현하기

4.1 인터페이스 정의

// Subject 인터페이스 (발행자)
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

// Observer 인터페이스 (구독자)
public interface Observer {
    void update(float temperature, float humidity, float pressure);
}

4.2 ConcreteSubject 구현

import java.util.ArrayList;
import java.util.List;

// 구체적인 Subject (WeatherData)
public class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;
    
    public WeatherData() {
        observers = new ArrayList<>();
    }
    
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    
    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }
    
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }
}

4.3 ConcreteObserver 구현

// 구체적인 Observer (현재 상태 디스플레이)
public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Subject weatherData;
    
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
    
    public void display() {
        System.out.println("현재 상태: 온도 " + temperature + "C, 습도 " + humidity + "%");
    }
}

4.4 실행 코드

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        
        weatherData.setMeasurements(25.5f, 65.0f, 1013.1f);
        weatherData.setMeasurements(27.0f, 70.0f, 1012.5f);
    }
}

실행 결과

현재 상태: 온도 25.5C, 습도 65.0%
현재 상태: 온도 27.0C, 습도 70.0%

5. 옵저버 패턴의 장점과 단점

✅ 장점

  • 느슨한 결합(Loose Coupling): Subject와 Observer가 독립적으로 동작하며, 한 쪽의 변경이 다른 쪽에 큰 영향을 미치지 않습니다.
  • 확장성: 새로운 옵저버를 쉽게 추가할 수 있습니다.
  • 재사용성: 여러 개의 옵저버를 재사용할 수 있습니다.

❌ 단점

  • 예측하기 어려움: 옵저버가 많아질수록 어떤 순서로 업데이트가 수행되는지 예측하기 어렵습니다.
  • 성능 문제: 옵저버 수가 많아질수록 Subject에서 변경이 발생할 때 성능 저하가 발생할 수 있습니다.
  • 메모리 누수 위험: 옵저버 등록을 해제하지 않으면 메모리 누수가 발생할 수 있습니다.

6. 정리

옵저버 패턴은 이벤트 기반 프로그래밍에서 자주 사용되는 강력한 디자인 패턴입니다. 특히 GUI 프로그래밍, 실시간 데이터 스트리밍, 메시지 브로커 시스템 등에서 효과적입니다. 하지만 옵저버 등록 해제 및 성능을 고려하여 신중하게 설계하는 것이 중요합니다.

profile
하리보의 개발 블로그

0개의 댓글