일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 운영체제
- AVL트리
- 점근적 표기법
- 알고리즘
- 엔티티 그래프
- heapq
- 백준 장학금
- HTTP
- JVM
- jpa n+1 문제
- 완전이진트리
- 강화학습
- 프로세스
- 최소힙
- MSA
- 자료구조
- posix
- JPA
- python
- 스케줄링
- Kruskal
- 힙트리
- SpringSecurity
- 멀티프로세서
- spring
- 연결리스트
- 연결리스트 종류
- 백준장학금
- 최대 힙
- 이분탐색이란
- Today
- Total
KKanging
[디자인 패턴] 센서 디스플레이 예제로 배우는 Observer Pattern 본문
센서 디스플레이 예제
가정

- WeatherData
- Display 종류
이 세 가지 메서드는 각각 가장 최근의 온도, 습도, 그리고 기압 측정값을 반환한다. 우리는 이러한 변수들이 어떻게 설정되는지 신경 쓸 필요가 없으며, WeatherData 객체가 외부 장치인 WeatherStation으로부터 업데이트된 정보를 얻는 방법을 알고 있다.
요구 사항
- 이 화면들은 WeatherData가 새로운 측정값을 받을 때마다 업데이트되어야 한다.
- 시스템은 확장 가능해야 한다
일단 구현

public class WeatherData {
private CurrentConditionDisplay currentConditionDisplay;
private StatisticsDisplay statisticsDisplay;
private ForecastDisplay forecastDisplay;
public WeatherData(CurrentConditionDisplay currentConditionDisplay, StatisticsDisplay statisticsDisplay, ForecastDisplay forecastDisplay) {
this.currentConditionDisplay = currentConditionDisplay;
this.statisticsDisplay = statisticsDisplay;
this.forecastDisplay = forecastDisplay;
}
public void measurementsChanged() {
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionDisplay.update(temp,humidity,pressure);
statisticsDisplay.update(temp,humidity,pressure);
forecastDisplay.update(temp,humidity,pressure);
}
}
getXXXX는 외부 시스템에서 온도, 습도 ,기압을 가지고 오는 함수이다
해결 했는가?
위 코드는 잘 돌아갈지 모르나 큰 단점을 가지고 있다.
만약 Display 가 하나 더 추가 된다면?
Display가 추가된다면 WeatherData를 수정해야 한다.
WeatherData 멤버 변수에 추가된 Display를 추가하고 update 로직을 measurementsChanged 함수 안에 작성해야 한다.
만약 Display 를 제거 해야한다면?
WeatherData 멤버 변수에 해당 Display 변수를 제거하고 추가 했던 것처럼 measurementsChanged 함수 안에 update 로직을 제거해야한다.
기존 Display 가 추가 되거나 삭제 했을 때 WeatherData의 로직을 변경하지 않으면서 WeatherData 의 상태가 변경되면 해당 상태를 관찰해야하는 다수의 Display가 알게 할 수 없을까?
Observer Pattern
Observer Pattern 이란

- 주제(Subject): 상태를 관리하고, 상태가 변경되면 옵저버들에게 그 변화를 알린다. 주제는 여러 옵저버를 등록하거나 제거할 수 있다.
- 옵저버(Observer): 주제의 상태 변화를 감지하고, 그에 따라 행동을 취한다. 주제와 느슨하게 결합되어 있어, 주제가 어떤 구체적인 옵저버인지 알 필요 없이 인터페이스를 통해 알림을 받는다.
목적
한 객체의 상태가 변화할 때, 이를 감지한 하나 이상의 객체가 자동으로 반응하도록 한다. 이를 통해 수동적인 행동 호출이 아닌 자동적인 변화나 알림을 가능하게 하여, 객체 간의 상호작용을 보다 효율적으로 관리하게 한다.
사용시기
- 상태 변화가 다른 객체에 영향을 줄 때: 한 객체의 상태가 변함에 따라 다른 객체의 행동이 변화해야 할 때, 옵저버 패턴을 적용하면 효과적이다. 예를 들어, 특정 주식의 가격이 오르면 이를 구독한 투자자들에게 알림이 가도록 설정할 수 있다.
- 행동에 대한 느슨한 결합이 필요할 때: 상태 변경이 특정 행동을 유발할 때, 이러한 행동과 상태 변경 간의 결합을 느슨하게 유지해야 할 경우, 옵저버 패턴이 적합하다. 객체들이 서로에 대해 직접적으로 의존하지 않고, 대신 인터페이스를 통해 상호작용하므로 유지보수와 확장성이 용이해진다.
- 1대다 통신이 필요할 때: 한 객체가 여러 객체에 상태 변화를 알릴 필요가 있을 때, 옵저버 패턴은 효과적인 해결책을 제공한다.
Observer Pattern 적용

public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
public class WeatherData implements Subject {
private float temperature;
private float humidity;
private float pressure;
private ArrayList<Observer> observers;
public WeatherData() {
observers = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if(i>=0) observers.remove(i);
}
@Override
public void notifyObservers() {
for(int i = 0; i < observers.size(); i++) {
Observer observer = observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temperature,float humidity, float pressure){
this.temperature=temperature;
this.humidity=humidity;
this.pressure=pressure;
measurementsChanged();
}
}
public interface Observer {
void update(float temp, float humidity, float pressure);
}
public class CurrentConditionDisplay implements Display, Observer {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
public class StatisticsDisplay implements Display, Observer {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public StatisticsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.println("Statistics: Avg/Max/Min temperature = " + temperature + "/" + humidity + "/" + pressure);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}
public interface Display {
void display();
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
'백엔드 > 아키텍처 & 패러다임 & 디자인 패턴' 카테고리의 다른 글
설계 원칙 , 전지적 2년차 뉴비 시점 (0) | 2025.04.07 |
---|---|
[디자인패턴] 음료시스템 예제로 배우는 Decorator Pattern (0) | 2024.10.24 |
[디자인 패턴] 오리 예제로 알아보는 Strategy Pattern (0) | 2024.10.11 |
자바 개발자가 AOP를 공부 해야하는 이유 (1) | 2024.09.26 |