2장 - 옵저버 패턴
옵저버 패턴이란?
옵저버패턴 클래스 다이어그램
신문사 + 구독자 = 옵저버 패턴
- 신문사는 주제(subject), 구독자를 옵저버(observer)라고 부른다.
- 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에 연락이 가고 자동으로 내용이 갱신되는 방식으로 다대다 의존성을 정의합니다.
- 옵저버 패턴은 보통 주제 인터페이스와 옵저버 인터페이스가 들어있는 클래스 디자인으로 구현합니다.
- 옵저버로 등록하거나 탈퇴하고 싶은 경우
Subject
인터페이스에 있는 메소드를 사용합니다. - 옵저버가 될 가능성이 있는 객체는
Observer
인터페이스를 구현해야합니다.- 주제의 상태가 바뀌었을 때 호출되는 update() 메소드만 구현
- 옵저버에는 데이터를 보내주는 푸시(push) 방식과 옵저버가 데이터를 가져오는 풀(pull) 방식으로 구분할 수 있습니다.
- Push 방식의 경우 매게변수가 변경될 가능성이 있다.
- Pull 방식의 경우 옵저버가 필요한 데이터를 가져올 수있기 때문에 더 느슨하게 결합될 수 있다.
- 대체로 옵저버가 필요한 데이터를 가져오도록 하는게 더 좋은 방법입니다.
느슨한 결합
느슨한 결합은 객체들이 상호작용 할 수는 있지만, 서로를 잘 모르는 관계를 의미합니다.
→ 느슨할 결합을 이용하면 유연성이 아주 좋아짐
주제는 옵저버가 특정 인터페이스를 구현한다는 사실만 알고있습니다.
새로운 옵저버가 추가될때도 주제는 신경쓸 필요없이
Observer
인터페이스만 구현되어 있으면 됩니다.주제나 옵저버를 다은 용도로 활용할 일이 있다고 해도 손쉽게 재활용이 가능합니다.
서로 느슨하게 결합되어 있으므로 주제나 옵저버 인터페이스를 구현한다는 조건만 만족한다면 어떻게 고쳐도 문제가 생기지 않습니다.
요구사항
Weather-O-Rama의 차세대 인터넷 기반 기상 스테이션 구축 시스템
기상정보 객체 다이어그램
호출되는 객체의 메소드
- Weather-O-Rama와 계약을 체결하면 WeatherData 객체를 통해 현재 조건, 기상통계, 기상 예보 이 3가지 디스플레이에 갱신하며 보여주어야 함
- 기상 관측이 변경된다면
measurementsChanged()
가 호출된다. - 다른 개발자가 새로운 디스플레이를 추가할 수 있고, 이후 화면에 몇가지의 항목들이 더 추가 될 수 있음
해결 방법 1 : 메소드 직접 호출
첫번째 해결 방법은 아주 단순하게 measurementsChanged()
메소드에 디스플레이 객체의 메소드를 직접호출하는 방법이다.
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);
}
}
단점
- 디스플레이 객체가 변경될 수도 있다.
- 바뀔 수 있는 부분은 캡슐화 해야한다.
- 구체적인 구현에 맞춰 코딩했으므로 프로그램을 고치지 않고는 다른 디스플레이 항목을 추가할 수 없다.
- 실행 중 디스플레이 객체를 더하거나 뺄수없다.
해결 방법 2 : 옵저버 패턴 적용
이제 옵저버 패턴을 적용해 느슨한 결합을 만족시키고, 확장성을 지니도록 변경해보겠습니다.
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
주제가 되는 인터페이스
public interface Observer {
// push 방식
void update(float temperature, float humidity, float pressure);
// pull 방식
void update();
}
옵저버 인터페이스
public interface DisplayElement {
void display();
}
디스플레이 인터페이스
public class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
this.observers = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(observers.indexOf(o));
}
@Override
public void notifyObservers() {
// 실질적인 옵저버의 호출을 담당
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
float getTemperature() {
return temperature;
}
float getHumidity() {
return humidity;
}
float getPressure() {
return pressure;
}
void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
...
}
주제를 구현한 WeatherData 클래스
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);
}
// 푸시 방식을 경우
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
// 풀 방식을 경우
@Override
public void update() {
this.temperature = weatherData.getTemperature();
this.humidity = WeatherData.getHumidity();
display();
}
@Override
public void display() {
System.out.println("현재 상태: 온도 " + temperature
+ "F, 습도 " + humidity + "%");
}
}
옵저버 디스플레이
장점
- 객체들간 느슨한 결합을 이뤄내었기 때문에 각자의 책임에만 집중하면 된다.
- 런타임 도중에도 옵저버 객체를 추가하거나, 삭제할 수 있다.
- 옵저버 객체도 주제 인터페이스를 구현한다면 주제이자 옵저버가 될 수 있다.
정리
- 옵저버 패턴은 객체들 사이에 일대다 관계를 정의합니다.
- 옵저버 패턴을 사용하면 주제가 데이터를 보내거나 옵저버가 데이터를 가져올 수 있지만 일반적으로 데이터를 가져오는게 더 옳은 방식입니다.
- 옵저버 패턴은 자주 사용되는 패턴으로 MVC를 배울때도 다시 거론됩니다.
'CS 지식 공부방 > 디자인패턴' 카테고리의 다른 글
[헤드퍼스트 디자인패턴 1장] 전략패턴 (0) | 2022.06.13 |
---|