Design Pattern : Observer pattern
Observer Pattern
-
한 객체의 상태가 바뀌면 그 객체가 의존하는 다른 객체들에게 연락이 가고 자동으로 내용이 갱신되는 방식
-
일대다(one-to-many)의 의존성을 정의한다.
-
상태를 저장하고 있는 주제(Subject) 인터페이스를 구현한 하나의 주제(Subject) 객체와 의존하고 있는 옵저버(Observer) 인터페이스를 구현한 여러개의 옵저버(Observer) 객체가 있다.
-
데이터 전달 방식
- 주제 객체에서 옵저버로 데이터를 보내는 방식(Push)
- 옵저버에서 주제 객체의 데이터를 가져가는 방식(Pull)
-
옵저버 패턴은 주제와 옵저버가 느슨하게 결합되어 있는 객체 디자인을 제공
-
디자인 원칙
서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게(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); //디스플레이 갱신
}
}
옵저버 패턴 구현
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);
}
}