본문 바로가기
Design Pattern/행동 패턴(Behavioral Patterns)

옵저버(Observer) - 행동 패턴(Behavioral Patterns)

by 김 민 준 2024. 5. 25.

 

 

옵저버 패턴은 개체의 상태 변화를 관찰하고, 그 변화가 발생했을 때 자동으로 통지(Notify)를 받아 처리할 수 있도록 하는 패턴이다. 주로 이벤트 기반 시스템에서 사용된다.

 

주요 개념부터 살펴보자

 

1. Subject (주제) : 상태를 가지고 있으며, 상태 변화를 옵서버들에게 알린다. 옵서버를 등록하고 제거하는 메서드를 제공한다. 

2. Observer (옵저버) : 주제의 상태 변화를 관찰하고, 상태 변화가 발생했을 때 특정 행동을 수행한다. 

3. ConcreteSubect (구체적인 주제 : 상태를 저장하고, 상태가 변경될 때 옵서버들에게 알린다.

4. ConcreteObserver (구체적인 옵서버) : 주제의 상태 변화를 관찰하고, 상태가 변경될 때 행동을 수행한다.

 

날씨 모니터링 시스템 소스코드를 통해서 옵서버 패턴에 대해서 조금 더 알아보자.

 

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

// Subject 인터페이스: 옵서버를 등록, 제거하고 알리는 메서드를 정의
interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

 

// WeatherData 클래스: 구체적인 주제 역할을 하며, 옵서버를 등록, 제거하고 상태 변화를 알림
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;
        measurementsChanged();
    }

    public void measurementsChanged() {
        notifyObservers();
    }
}

 

// Observer 인터페이스: 주제의 상태가 변경될 때 업데이트되는 메서드를 정의
interface Observer {
    void update(float temperature, float humidity, float pressure);
}

 

// CurrentConditionsDisplay 클래스: 구체적인 옵서버 역할을 하며, 상태 변경 시 행동을 수행
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("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}

 

// Client 클래스: WeatherData 객체를 생성하고, CurrentConditionsDisplay 옵서버를 등록하고 상태를 변경
public class ObserverPatternDemo {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);
    }
}

 

//출력 

//Current conditions: 80.0F degrees and 65.0% humidity
//Current conditions: 82.0F degrees and 70.0% humidity
//Current conditions: 78.0F degrees and 90.0% humidity

 

온도 변화를 감지하고 여러 디스플레이장치에 온도 변화를 알리는 예시소스코드를 확인할 수 있다.

 

실무에서도 아주 많이 사용된다. 몇가지만 살펴 보자 

 

1. 이벤트 핸들링 시스템 

- 예를 들어 하나의 GUI 애플리캐이션이 있다고 하자. 키보드 입력 등 다양한 이벤트를 처리해야하는데 이때 자바로 프로그래밍 되어 있다면 ActionListener를 많이 사용한다. ActionListener가 옵서버 패턴을 사용하고 있다.

 

2. MVC 아키텍처 

- 과거도 현재도 가장 많이 사용되는 MVC 아키텍처는 모델과 뷰 사이에 상호작용되는데 모델의 상태가 변경될때 뷰에 자동으로 통지하여 화면을 갱신하는 구조이다. 이역시 옵서버 패턴이다.

 

3. 실시간 데이터 피드

- 주식 시세, 뉴스 피드, 소셜 미디어 업데이트 등 실시간 데이터 변경을 구독자에게 통지할 때 사용된다.

 

4. 알림 시스템

- 이메일 SMS 푸시 알림 등 다양한 채널을 통해 알림을 전송할 때 사용한다.

 

이렇게 보면 현대에서는 AWS를 많이 사용하고 AWS의 SNS가 떠오를 수 있다.

 

맞다. AWS 의 SNS는 옵서버 패턴과 아주 유사하다.

 

AWS 의 Topic은 옵서버 패턴의 Subject와 같은 역할을 한다. 또한 Observer는 SNS에서 Subscribers이다. 그리고 Notification이 전송되는 구조이다.

 

그러면 AWS SQS는 어떨까? 

SQS 는 생산자-소비자 패턴이기에 Producer - Consumer 구조에서는 큐에 저장하고 소비자가 읽을떄까지 보관하는것이다. 그렇기에 메시지 전달을 보장한다. 옵서버 패턴과는 다르지만 헛갈릴 수 있는 부분이다. 대부분 큐에 저장한것을 바로바로 읽어가는쪽으로 대부분의 기존 시스템들을 설계하고 구현했을테니 처음 접하거나 업력이 아직 얼마 안되었다면 헛갈릴 수 있다. 큐잉 메커니즘에 대해서는 별도로 학습하길 권장한다.

 

옵서버 패턴을 생각하지 않아도 본인 스스로 자주 쓰이는 경우가 많다.

비동기 프로그래밍을 할때이다. 자바스크립트 기준으로 Promise개체와 async/await 구문 역시 옵서버 패턴과 유사하다. 

이벤트 버스도 비슷하다. 그만큼 옵서버 패턴은 자주 쓰이기도하고 본인도 모르게 유사하게 구조를 잡아가면서 구현하는 경우가 있다.