이 포스트는 한빛미디어 'HeadFirst - Design Pattern' 을 공부하면서 작성되었습니다.
이전 포스트에서 구현했던 Subject 인터페이스 대신, Observable 클래스를 통해 옵저버 패턴을 구현할 수 있다.
java.util.Observer, java.util.Observable 을 이용하면 된다.
Class Observable | Class WeatherData : Observable 를 확장한 Class (Observable Object) |
addObserver() deleteObserver() notifyObserver() setChanged() |
getTemperature() getHumidity() getPressure() |
Interface Observer | GeneralDisplay StatisticsDisplay ForecastDisplay : Observer 를 구현하는 Concrete Class |
update() | update() display() |
Class Observable, Interface Observer 구조를 가진 자바 내장 옵저버 패턴은 이전 글에서 직접 구현한 옵저버 패턴과 약간 다르다.
WeatherData 가 Observable Class 를 확장하고 add/delete/notify 와 같은 methods 를 상속한다는 점이 가장 다르다.
Object 이 observer 가 되기 위해 ..
java.util.Observer interface 를 구현한 후, Observable object 에서 addObserver()를 부른다. 마찬가지로 어떤 observer 를 삭제하기 위해 deleteObserver()를 부른다.
Observable 이 알람을 보내기 위해 ..
java.util.Observable superclass 를 확장하여 Observable 로 만든 후, 아래 두 단계를 수행한다.
1. setChanged() method 실행, 객체에서 상태가 바뀌었다는 것을 표시하기 위해,
2. 두 notifyObservers() methods 중 하나 실행 (notifyObservers() or notifyObservers(Object arg)
Observer 가 알람을 받기 위해 ..
Observer 는 update method를 구현하는데, 약간 다르다. observer들에게 데이터를 보내고 싶다면(push), notifyObservers(arg) method로 데이터를 넘기면 된다. 메세지 전송을 관두고 싶다면(pull), Observable object 가 데이터를 넘겼던 곳으로부터 Observer는 데이터를 빼낸다.
setChanged() -> notifyObservers() : 날씨 상태가 바뀌었으며, 그 정보를 observer들에게 업데이트 함
setChanged() 가 불리지 않고 notifyObservers() : observer들은 알람을 받지 않음
ㅇㅗㅏ 먼말이야 구현을 먼저 보자
// Observable : superClass
import java.util.Observable;
// superClass의 subClass 생성 : WeatherData
public class WeatherData extends Observable {
// 우리는 더이상 observer 등록/삭제/알람 관리를 직접 할 필요가 없다.
private float temperature;
private float humidity;
private float pressure;
// 더이상 Observers에게 연락하기 위해 data structure를 생성할 필요가 없다.
public WeatherData() {}
public void measurementsChanged() {
// 이제 notifyObservers 호출을 통해 data 객체를 보내지 않고, PULL 모델을 쓴다.
setChanged();
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;
}
}
Current Display 모듈
import java.util.Observable;
import java.util.Observer;
public class CurrentConditionDisplay implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;
public CurrentConditionDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable obs, Object arg) {
if(obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
// Tmep, Humidity 정보를 업데이트
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current condition: " + temperatur + "F degrees and "
+ humidity + "% humidity");
}
}
Forecast Display 모듈
import java.util.Observable;
import java.util.Observer;
public class ForecastDisplay implements Observer, DisplayElement {
Observable observable;
private float currentPressure = 29.92f;
private float lastPressure;
public ForecastDisplay(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
public void update(Observable observable, Object arg) {
if(observable instanceof WeatherData) {
WeatherData weatherData = (WeatherData)observable;
// 마지막 기압과 현재 기압 저장
lastPressure = currentPressure;
currentPressure = weatherData.getPressure();
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");
}
}
}
테스트 결과 :
직접 구현한 옵저버패턴의 결과와 순서가 다름
Forecast -> Statistics -> Current
registerObserver 에서 데이터를 저장하는 순서가 다르기 때문?!
사실 자바 내장 옵저버패턴은 몇 가지 불편한 점이 있다.
1. Observable 은 class 다. interface가 아니고
Observable 이 class이기 때문에 이것을 subclass 해야한다. 그러면 Observable behavior 에 추가하는 작업을 할 수 없다. WeatherData subclass는 이미 Observable superclass 를 extend 하기 때문에, 이 subclass 에 behavior를 추가할 수 없는 것.
2. Obsevable 이 crucial methods 를 방지한다.
setChanged() 함수는 Observable API 이기 때문에, Observable 을 subclass 하지 않으면 이 함수를 호출할 수 없다.
'성장하는 중 입니다? > 디자인패턴' 카테고리의 다른 글
옵저버 패턴 (0) | 2021.07.07 |
---|