본문 바로가기
디자인 패턴

4. Observer Pattern

by spaul 2023. 11. 7.

▣ What is Observer Pattern?

Define a one-to-many dependency between objects so that when one object changes state, all its dependent are notified and updated automatically.

 

 옵저버 패턴은 객체간 1:多 의존 관계를 정의하여, 한 개의 객체 상태가 변경될 때, 그 객체와 의존 관계에 있는 모든 객체들이 자동으로 알림을 받고 상태를 갱신하는 패턴입니다.

 

옵저버 패턴은 일종의 push서비스와 비슷하다고 할 수 있습니다. 우리가 어떤 유튜브 채널을 구독했을 때, 그 유튜브에 새로운 영상이 업로드 되었는지 아닌지 계속 들어가서 확인하는 것은 번거롭겠죠? 그럴 때, 우리는 유튜브 채널을 구독한 다음 채널에 새로운 영상이 업로드되면 알림이 오도록 설정할 수 있습니다.

 

 옵저버 패턴은 이처럼 주체(Subject)푸쉬를 받고자 하는 사용자(Observer)가 등록하고, 특정 상황이 발생하면 등록된 사용자에게 모두 알리고 자동으로 데이터가 갱신되도록 하는 패턴입니다.

 

 

 위 그림에서 볼 수 있듯, Subject에서 Observer를 등록 또는 해제하고, 객체의 상태가 변경되어 옵저버에게 알려야 할 내용이 있다 notifyObservers()를 통해 옵저버에게 객체의 변경 상태를 알려줍니다. 

 

 간단한 프로그램을 통해 옵저버 패턴에 대해 좀 더 알아보겠습니다. 현재 온도, 습도, 기압과 같은 날씨 정보를 알려주는 Subject가 있고, 이 Subject에 Observer들이 등록하여 날씨 정보가 변경 될 때마다 Observer들에게 알려주는 프로그램을 만드려고 합니다. 

 

 그러면 우선 옵저버를 등록하는 메서드, 제거하는 메서드, 그리고 변경된 상태를 알려주는 메서드가 필요할 것 같고, 현재 날씨 정보를 받아 오는 메서드가 필요할 것 같습니다. 그리고 옵저버에는 변경된 날씨 정보만 알려주면 되므로 update() 메서드만 추가하면 될 것 같습니다.  

// WeatherData.java
import java.util.*;
public class WeatherData implements Subject {
    private ArrayList<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList<Observer>();
    }

    public void registerObserver(Observer o) {
        observers.add(o);
    }

    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = observers.get(i);
            observer.update(temperature, humidity,
                    pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature,
                                float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }
    public float getHumidity() {
        return humidity;
    }
    public float getPressure() {
        return pressure;
    }
}

 

  다른 메서드들의 대한 설명은 생략하고, WeatherData의 setMeasurements() 메서드를 보시면 현재 객체의 상태가 변경(set)되면 변경된 정보들을 measurementsChanged()를 통해 Observer들에게 notify 해주는 것을 확인할 수 있습니다.

 

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    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();
    }

    @Override
    public void display() {
        System.out.println("Current conditions: "
                + temperature + "F degrees and " + humidity
                + "% humidity");
    }
}

 

 그 다음 CurrentConditionDisplay 클래스가 하나의 Observer가 됩니다. 이 클래스에서 update()를 구현하여 weatherData 객체의 상태가 변경될 때마다 display하도록 합니다.

// WeatherStation.java
import java.util.*;

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 1013);
        weatherData.setMeasurements(82, 70, 1015);
        weatherData.setMeasurements(78, 90, 1010);
    }
}

 

 위의 main()이 포함된 WeatherStation클래스를 실행하면 아래와 같이 실행되는 것을 확인할 수 있습니다.

 

 

WeatherDate의 프로그램의 전체적인 클래스 다이어그램은 아래와 같습니다.

 

References

[1] 조용주, 고급객체지향프로그래밍

[2] Eric Freeman, Head Frist Design Patterns

'디자인 패턴' 카테고리의 다른 글

6. Iterator Pattern  (0) 2023.11.14
5. Singleton Pattern  (0) 2023.11.13
3. Strategy Pattern  (0) 2023.10.29
2-2. SOLID(S.O.L.I.D)  (0) 2023.10.18
2-1. SOLID(S.O.L.I.D.)  (0) 2023.10.16