Notice
suyeonme
[디자인 패턴] 옵저버 패턴(Observer Pattern) 본문
헤드 퍼스트 디자인 패턴을 읽고 정리한 내용입니다.
1. 문제 상황
1. WeatherData 객체는 물리 기상 스테이션과 통신해서 갱신된 기상 데이터를 가져온다.
2. 복수개의 디스플레이는 WeatherData 객체의 기상데이터를 사용한다.
3. 따라서 WeatherData 객체의 기상 데이터가 업데이트될 때마다 디스플레이 장비의 데이터 또한 업데이트해야한다.
2. 문제 해결 시도
가장 간단한 방법으로 아래와 같이 구현할 수 있다. 이 때 각각의 display에서 update()를 호출하는 부분은 구체적인 구현에 맞춰서 코드가 작성되었으므로 프로그램을 고치지 않고서는 다른 디스플레이 항목을 추가하거나 제거할 수 없다. 따라서 해당 부분은 캡슐화가 필요하다.
public class WeatherData {
// 인스턴스 변수 선언
public void measurementsChanged() {
// 기상 데이터가 업데이트 될 때마다 호출
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionsDisplay.update(temp, humidity, pressure);
statisticDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}
}
3. 옵저버 패턴으로 문제 해결
3.1 옵저버 패턴(Observer Pattern)이란?
한 객체(subject)의 상태가 바뀌면 그 객체에 의존하는 다른 객체(observer)에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one to many)의존성을 정의한다.
3.2 Push방식으로 구현
주제(subject)의 데이터가 바뀌면 update()를 호출해서 자동으로 옵저버(observer)에 업데이트된 내용을 보낸다.
1. 인터페이스 정의하기
// 인터페이스 정의
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers(); // 주제의 상태가 변경되었을 때 변경 내용을 알림
}
public interface Observer {
public void update(float temp, float humididy, float pressure);
}
public interface DisplayElement {
public void display();
}
2. Subject 인터페이스 구현하기
public class WeatherData implements Subject {
private List<Observer> observesrs;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<Observer>();
}
public registerObserver(Observer o) {
observers.add(o);
}
public removeObserver(Observer o) {
observers.remove(o);
}
public notifyObservers() {
for(Observer observer : observers) {
observers.update(temperature, humidity, pressure);
}
}
public measurementsChanged() {
notifyObservers();
}
public setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
}
}
3. 디스플레이 요소 구현하기
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private WeatherData = weatherData;
public CurrentConditionsDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this); // 옵저버로 추가
}
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public display() {
System.out.println("현재 상태: 온도 " + temperature + "F, 습도 " + humidity + "%");
}
}
4. 기상 스테이션 테스트
public class WeatherStation {
WeatherData weatherData = new WeatherData();
// 디스플레이 생성
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
StatisticDisplay statisticDisplay = new StatisticDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
currentDisplay.setMeasurements(80, 65, 30.4f);
statisticDisplay.setMeasurements(82, 70, 31.2f);
forecastDisplay.setMeasurements(78, 61, 29.4f);
}
3.3. Pull 방식으로 구현
옵저버(observer)가 필요할 때마다 주제(subject)로부터 데이터를 당겨오는 방식이다.
// 1. Subject의 메소드 수정
public notifyObservers() {
for(Observer observer : observers) {
observers.update();
}
}
// 옵저버 인터페이스 수정
public interface Observer {
public void update();
}
// 옵저버의 update 함수 수정
public void update() {
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
'프로그래밍👩🏻💻 > 디자인 패턴' 카테고리의 다른 글
[디자인 패턴] 커맨드패턴(Command Pattern) (0) | 2022.07.10 |
---|---|
[디자인 패턴] 싱글톤 패턴(Singleton Pattern) (0) | 2022.07.04 |
[디자인 패턴] 팩토리 패턴(Factory Pattern) (0) | 2022.06.26 |
[디자인 패턴] 데코레이터 패턴(Decorator Patter) (0) | 2022.06.19 |
[디자인 패턴] 전략 패턴(Strategy Pattern) (0) | 2022.06.18 |
Comments