관리 메뉴

bright jazz music

Observer Pattern 1. 옵저버 패턴 본문

Design Pattern/Observer Pattern

Observer Pattern 1. 옵저버 패턴

bright jazz music 2022. 11. 7. 15:22

옵저버 패턴

 

  • 옵저버 패턴은 객체들 사이에 일대다 관계를 정의한다. (Subject --> observers)
  • 주제는 동일한 인터페이스를 써서 옵저버에게 연락한다.
  • Observer 인터페이스를 구현하기만 하면 어떤 구상클래스의 옵저버라도 패턴에 참여할 수 있다.
  • 주제는 옵저버들이 Observer인터페이스를 구현한다는 것을 제외하면 옵저버에 관해 전혀 모른다. 따라서 이들 사이의 결합은 느슨한 결합(loose coupling)이다.
  • 옵저버 패턴을 사용하면 주제가 데이터를 보내거나(푸시 방식) 옵저버가 데이터를 가져올(풀 방식) 수 있다. 일반적으로 풀 방식이 더 옳은 방식이라고 간주한다.
  • 스윙은 다른 여러 GUI프레임워크처럼 옵저버 패턴을 많이 사용한다.
  • RxJava, 자바빈, RMI 외에 코코아나 스위프트, 자바스크립트와 같은 다른 언어의 프레임워크에서도 옵저버 패턴을 많이 사용한다.
  • 옵저버 패턴은 여러 개의 주제와 메시지 유형이 있는 복잡한 상황에서 사용하는 출판-구독 패턴과 친척이다.
  • 옵저버 패턴은 MVC 패턴과 깊은 연관이 있다.

 

//Subject.java

package com.example.designpatternstudy.observerPattern;

public interface Subject {
    public void registerObserver(ObserverForObserverPattern observer);
    public void removeObserver(ObserverForObserverPattern observer);

    //주제의 상태가 변경되었을 때 모든 옵저버에게 변경내용을 알리기 위해 호출되는 메소드
    public void notifyObservers();
}

 

 

//Subject 인터페이스 구현하기

package com.example.designpatternstudy.observerPattern;

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

public class WeatherData implements Subject{ //Subject인터페이스 구현
    private List<ObserverForObserverPattern> observers;
    private float temperature;
    private float humidity;
    private float pressure;

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

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

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

    @Override
    public void notifyObservers() {
        //모든 옵저버에게 상태 변화를 알려주는 부분
        //모두 ObserverForObserverPattern인터페이스를 구현하는 객체들이므로
        //update()메소드를 통해 손쉽게 상태 변화를 알려줄 수 있다.
        for (ObserverForObserverPattern observer : observers) {
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measuirementsChanged(){
        notifyObservers();
    }

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

        measuirementsChanged();
    }



}

 

 

//CurrentConditionDisplay.java

package com.example.designpatternstudy.observerPattern;

//weatherData객체로부터 변경사항을 받으려면 ObserverForObserverPattern을 구현해야 한다.
// API구조상 모든 디스플레이 항목에서 DisplayElement를 구현하기로 했기에 DisplayElement도 구현한다.

public class CurrentConditionDisplay implements ObserverForObserverPattern, DisplayElement{

    private float temperature;
    private float humidity;
    private WeatherData weatherData;

    //생성자에 weatherData라는 주제(Subject)가 전달되며, 그 객체를 써서 디스플레이를 옵저버로 등록한다.
    public CurrentConditionDisplay(WeatherData weatherData){
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    @Override //ObserverForObserverPattern으로부터
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }

    @Override //DisplayElement로부터
    public void display() { // 가장 최근에 받은 온도와 습도 출력
        System.out.println("현재 상태: 온도 "
                + temperature + "F, 습도 " + humidity + "%");

    }


}

 

 

package com.example.designpatternstudy.observerPattern;

public class StatisticsDisplay implements ObserverForObserverPattern, DisplayElement {
    private float maxTemp = 0.0f;
    private float minTemp = 200;
    private float tempSum= 0.0f;
    private int numReadings;
    private WeatherData weatherData;

    public StatisticsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    public void update(float temp, float humidity, float pressure) {
        tempSum += temp;
        numReadings++;

        if (temp > maxTemp) {
            maxTemp = temp;
        }

        if (temp < minTemp) {
            minTemp = temp;
        }

        display();
    }

    public void display() {
        System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings)
                + "/" + maxTemp + "/" + minTemp);
    }
}

 

 

package com.example.designpatternstudy.observerPattern;

public class ForecastDisplay implements ObserverForObserverPattern, DisplayElement {
    private float currentPressure = 29.92f;
    private float lastPressure;
    private WeatherData weatherData;

    public ForecastDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    public void update(float temp, float humidity, float pressure) {
        lastPressure = currentPressure;
        currentPressure = pressure;

        display();
    }

    public void display() {
        System.out.print("Forecast: ");
        if (currentPressure > lastPressure) {
            System.out.println("Improving weather on the way!");
        } else if (currentPressure == lastPressure) {
            System.out.println("More of the same");
        } else if (currentPressure < lastPressure) {
            System.out.println("Watch out for cooler, rainy weather");
        }
    }
}

 

package com.example.designpatternstudy.observerPattern;

public class WeatherStation {

    public static void main(String[] args) {

        //weatherData 객체 생성
        WeatherData weatherData = new WeatherData();

        CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);

        //3개의 디스플레이를 생성하고 weatherData 객체를 인자로 전달
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30.4f);
        //아래의 setMeasurements를 새로운 측정값으로 가정한다.
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);


    }


}

/*
> Task :WeatherStation.main()
현재 상태: 온도 80.0F, 습도 65.0%
Avg/Max/Min temperature = 80.0/80.0/80.0
Forecast: Improving weather on the way!
현재 상태: 온도 82.0F, 습도 70.0%
Avg/Max/Min temperature = 81.0/82.0/80.0
Forecast: Watch out for cooler, rainy weather
현재 상태: 온도 78.0F, 습도 90.0%
Avg/Max/Min temperature = 80.0/82.0/78.0
Forecast: More of the same

*/

 

Comments