디자인 패턴

Observer Pattern

kyoulho 2024. 5. 30. 22:35

옵저버 패턴은 객체 간에 일대다의 의존 관계를 정의하는 디자인 패턴이다.

이 패턴은 한 객체의 상태가 변경될 때, 그 객체에 의존하는 다른 객체들에게 알림을 전달하여 자동으로 상태를 갱신하도록 하는 것을 목적이다.

주체에서 옵저버에게 데이터를 푸시하는 방법과 주체에서 데이터 변경을 알리면 옵저버가 필요한 데이터를 가져가는 풀 방식이 있다.

 

데이터 전이 방식

  푸쉬 방식 풀 방식
장점 단순성
옵저버는 주제에서 직접 데이터를 전달받기 때문에,
주제의 상태를 쉽게 파악할 수 있다.
유연성
 옵저버가 필요한 데이터만 요청하여 가져올 수 있으므로,
불필요한 데이터 전송을 줄일 수 있다.
즉시성
데이터가 변경될 때마다 즉시 전달되므로,
옵저버는 항상 최신 상태를 반영한다.
독립성
주제의 내부 데이터 구조가 변경되더라도 옵저버에는 영향이 적다. 옵저버는 필요한 데이터를 요청하여 가져오기만 하면 된다.
단점 과도한 데이터 전달
 모든 옵저버에게 모든 데이터를 전달할 필요가 없는 경우에도 데이터를 전달하게 되어 비효율적일 수 있다.
복잡성 증가
옵저버가 주제의 상태를 가져오기 위해
추가적인 요청을 해야 하므로 코드가 복잡해질 수 있다.
유연성 부족
주제의 데이터 구조가 변경되면
옵저버도 그에 맞게 변경해야 하는 경우가 발생할 수 있다.
성능 문제
옵저버가 주제의 상태를 가져오기 위해
여러 번 호출할 경우, 성능 문제가 발생할 수 있다.
의존성 증가
주제와 옵저버 간의 의존성이 커질 수 있다.
주제의 데이터 형식이나 내용이 변경되면
옵저버 코드도 수정해야한다.
최신성 보장 어려움
옵저버가 주제의 상태를 가져오는 시점에 따라
최신 상태를 반영하지 못할 수 있다.
  • 푸쉬 방식은 간단하고 즉각적인 반응이 필요할 때 유용하지만, 데이터 전달의 효율성 면에서 비효율적일 수 있다.
  • 풀 방식은 옵저버와 주제 간의 결합도를 낮추고 유연성을 제공하지만, 코드 복잡성과 성능 면에서 단점이 있다.

 

구성 요소

  1. Subject(주체):
    • 상태를 가지고 있는 주체 객체.
    • 옵저버 객체들을 등록하고, 상태 변경 시 옵저버들에게 알림을 보내는 역할을 한다.
  2. Observer(옵저버):
    • 주체의 상태 변경을 감지하고 그에 따라 동작을 수행하는 객체.
    • 여러 개의 옵저버가 주체에 등록되어 있을 수 있다.
  3. ConcreteSubject(구체적인 주체):
    • Subject의 구체적인 구현 클래스로, 상태가 변경될 때마다 등록된 옵저버들에게 알림을 보낸다.
  4. ConcreteObserver(구체적인 옵저버):
    • Observer의 구체적인 구현 클래스로, 주체의 상태 변경에 따라 동작을 수행한다.

 

 

예제

// Observer 인터페이스는 옵저버 객체가 업데이트될 때 호출되는 메서드를 정의한다.
public interface Observer {
    // 푸시 방식의 update 메서드: 주제에서 전달하는 데이터를 인자로 받는다.
    void update(float temp, float humidity, float pressure);
    // 풀 방식의 update 메서드: 주제에서 데이터를 직접 가져온다.
    void update();
}

// DisplayElement 인터페이스는 화면에 표시하는 기능을 정의한다.
public interface DisplayElement {
    // display 메서드는 데이터를 화면에 표시한다.
    void display();
}

// Subject 인터페이스는 옵저버를 등록하고 제거하며, 상태가 변경되었을 때 옵저버에게 알리는 메서드를 정의한다.
public interface Subject {
    // 옵저버 등록
    void registerObserver(Observer observerPush);
    // 옵저버 제거
    void removeObserver(Observer observerPush);
    // 주제의 상태가 변경되었을 때 모든 옵저버에게 변경 내용을 알린다.
    void notifyObservers();
}

// WeatherData 클래스는 주제(Subject)를 구현하며, 날씨 데이터를 관리한다.
public class WeatherData implements Subject {
    private final List<Observer> observers; // 등록된 옵저버 목록
    private float temperature; // 현재 온도
    private float humidity;    // 현재 습도
    private float pressure;    // 현재 기압

    public WeatherData() {
        this.observerPushes = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            // 풀 방식
            observer.update();
            // 푸시 방식
            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;
    }
}

// Observer와 DisplayElement 인터페이스를 구현하며, 현재 날씨 상태를 표시한다.
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature; // 현재 온도
    private float humidity;    // 현재 습도
    private final WeatherData weatherData; // WeatherData 객체 참조

    // WeatherData 객체를 받아서 자신을 옵저버로 등록한다.
    public CurrentConditionsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.printf("현재 상태: 온도 %fF, 습도 %f%%", temperature, humidity);
    }

    // 푸시 방식의 업데이트 메서드: 주제에서 데이터를 받아서 필드를 업데이트하고 화면에 표시한다.
    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }

    // 풀 방식의 업데이트 메서드: 주제에서 데이터를 직접 가져와서 필드를 업데이트하고 화면에 표시한다.
    @Override
    public void update() {
        this.temperature = weatherData.getTemperature();
        this.humidity = weatherData.getHumidity();
        display();
    }
}

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

Singletone Pattern  (0) 2024.06.15
Proxy Pattern  (0) 2024.06.15
Mediator Pattern  (0) 2024.05.28
Iterator Pattern  (0) 2024.05.27
Flyweight Pattern  (0) 2024.05.25