Observer Pattern

  • 한 객체의 상태가 바뀌면 그 객체가 의존하는 다른 객체들에게 연락이 가고 자동으로 내용이 갱신되는 방식

  • 일대다(one-to-many)의 의존성을 정의한다.

  • 상태를 저장하고 있는 주제(Subject) 인터페이스를 구현한 하나의 주제(Subject) 객체와 의존하고 있는 옵저버(Observer) 인터페이스를 구현한 여러개의 옵저버(Observer) 객체가 있다.

  • 데이터 전달 방식

    • 주제 객체에서 옵저버로 데이터를 보내는 방식(Push)
    • 옵저버에서 주제 객체의 데이터를 가져가는 방식(Pull)

observer1

  • 옵저버 패턴은 주제와 옵저버가 느슨하게 결합되어 있는 객체 디자인을 제공

  • 디자인 원칙

    서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게(Loose) 결합하는 디자인을 사용해야 한다.

  • 느슨하게 결합하는 디자인을 사용하면 변경사항이 발생하여도 어렵지 않게 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있다.(객체 사이의 상호의존성을 최소화)

예시

  • 날씨 데이터를 가지고 있는 회사와 데이터를 연동하여 여러 종류의 각각의 디스플레이에 날씨데이터를 출력해줘야 하는 업무가 생겼다.
  • getTemperature() : 온도
  • getHumidity() : 습도
  • getPressure() : 기압
  • measurementsChanged() : 새로운 기상 측정 데이터가 나올때마다 자동으로 호출
public class WeatherData{
     public void measurementsChanged() { //새로운 데이터 세팅시 갱신되는 메소드
         float temp = getTemperature();
         float humidity = getHumidity();
         float pressure = getPressure();

         currentCondirionsDisplay.update(temp, humidity, pressure); //디스플레이 갱신
         statisticsDisplay.update(temp, humidity, pressure); //디스플레이 갱신
         forecastDisplay.update(temp, humidity, pressure); //디스플레이 갱신
     }
 }

observer2

옵저버 패턴 구현

observer3

 public interface Subject {
      void registerObserver(Observer observer);
      void removeObserver(Observer observer);
      void notifyObservers();
 } 

 public interface Observer {
      void update(float temp, float humidity, float pressure);
 }

 public interface DisplayElement {
      void display();
 }
public class WeatherData implements Subject{
	private List<Observer> observers;
	private float temperature;
	private float humidity;
	private float pressure;

	{
		this.observers = new ArrayList<>();
	}

	public void measurementsChanged(){ this.notifyObservers(); }
	public void setMeasurementsChanged(float t, float h, float p){	//값이 세팅된다고 가정.
		this.temperature = t;
		this.humidity = h;
		this.pressure = p;
		this.measurementsChanged();
	}

	@Override
	public void notifyObservers() {
		for (Observer observer : observers) {
			observer.update(this.temperature, this.humidity, this.pressure);
		}
	}

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

	@Override
	public void removeObserver(Observer observer) {
		if(observers.contains(observer)) observers.remove(observer);
	}
 }
public class CurrentConditions implements Observer, DisplayElement{
	private float temperature;
	private float humidity;
	private Subject weatherData;

	public CurrentConditions(Subject weatherData) {
		this.weatherData = weatherData;
		this.weatherData.registerObserver(this);	//옵저버 등록
	}

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

	@Override
	public void update(float temp, float humidity, float pressure) {
		this.temperature = temp;
		this.humidity = humidity;
		this.display();
	}
 }
 public class WeatherStation {
	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
		CurrentConditions currentConditions = new CurrentConditions(weatherData);
		StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
		ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
		weatherData.setMeasurementsChanged(85, 62, 36.7f);
	}
 }