// ❌ 나쁜 예: 강하게 결합된 코드
public class WeatherData {
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);
}
}
문제점:
public interface Subject {
void registerObserver(Observer o); // 구독 신청
void removeObserver(Observer o); // 구독 취소
void notifyObservers(); // 모든 구독자에게 알림
}
왜 Interface인가?
public interface Observer {
void update(float temp, float humidity, float pressure);
}
왜 Interface인가?
다중 구현 가능
// ✅ 가능: 하나의 객체가 Subject이면서 Observer가 될 수 있음
public class WeatherAlert implements Subject, Observer {
// 날씨를 관찰하면서 동시에 다른 객체들에게 알림
}
느슨한 결합
공통 구현이 없음

Subject (1) ────────> Observer (N)
(데이터 소유자) (데이터 사용자들)
- 일대다 관계
- Subject가 변경되면 자동으로 모든 Observer에게 알림
- Observer는 언제든 등록/해제 가능
// Subject 인터페이스
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// Observer 인터페이스
public interface Observer {
void update(float temp, float humidity, float pressure);
}
public class WeatherData implements Subject {
private ArrayList<Observer> observers; // Observer 목록
private float temperature;
private float humidity;
public WeatherData() {
observers = new ArrayList<Observer>();
}
// Observer 등록
public void registerObserver(Observer o) {
observers.add(o);
}
// Observer 제거
public void removeObserver(Observer o) {
observers.remove(o);
}
// 모든 Observer에게 알림 (핵심!)
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
// 데이터 변경 시 자동 알림
public void setMeasurements(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
notifyObservers(); // 자동으로 모든 Observer에게 알림
}
}
// 현재 날씨 표시
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
// 생성자에서 Subject에 등록
public CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this); // 나를 등록해줘!
}
// Subject로부터 알림 받음
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display(); // 자동으로 화면 업데이트
}
public void display() {
System.out.println("현재: " + temperature + "°F, " + humidity + "%");
}
}
// 통계 표시
public class StatisticsDisplay implements Observer {
private float maxTemp = 0.0f;
private float minTemp = 200.0f;
private float tempSum = 0.0f;
private int numReadings = 0;
public StatisticsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
public void update(float temp, float humidity, float pressure) {
tempSum += temp;
numReadings++;
if (temp > maxTemp) maxTemp = temp;
if (temp < minTemp) minTemp = temp;
display();
}
public void display() {
System.out.println("평균/최고/최저 = "
+ (tempSum/numReadings) + "/" + maxTemp + "/" + minTemp);
}
}
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
// Observer들 생성 (생성과 동시에 자동 등록)
CurrentConditionsDisplay currentDisplay =
new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay =
new StatisticsDisplay(weatherData);
// 데이터 변경 → 자동으로 모든 디스플레이 업데이트!
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
현재: 80.0°F, 65.0%
평균/최고/최저 = 80.0/80.0/80.0
현재: 82.0°F, 70.0%
평균/최고/최저 = 81.0/82.0/80.0
현재: 78.0°F, 90.0%
평균/최고/최저 = 80.0/82.0/78.0
import java.util.Observable;
import java.util.Observer;
// Subject 구현 (Observable 상속)
public class WeatherData extends Observable {
private float temperature;
private float humidity;
public void setMeasurements(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
setChanged(); // ⚠️ 중요: 변경 플래그 설정
notifyObservers(); // 알림 발송
}
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
}
// Observer 구현
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
public CurrentConditionsDisplay(Observable observable) {
observable.addObserver(this); // 등록
}
// Observable로부터 알림 받음
public void update(Observable obs, Object arg) {
if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("현재: " + temperature + "°F, " + humidity + "%");
}
}
setChanged()를 사용하는 이유:
| 요소 | 역할 | 왜 Interface? |
|---|---|---|
| Subject | Observer 관리 및 알림 발송 | 다양한 데이터 소스가 Subject가 될 수 있음 |
| Observer | 알림 수신 및 처리 | 다양한 방식으로 알림을 처리할 수 있음 |
| Concrete Subject | 실제 데이터 소유 | Subject를 구현 |
| Concrete Observer | 실제 동작 수행 | Observer를 구현 |