옵저버 패턴은 객체 간에 일대다의 의존 관계를 정의하는 디자인 패턴이다.
이 패턴은 한 객체의 상태가 변경될 때, 그 객체에 의존하는 다른 객체들에게 알림을 전달하여 자동으로 상태를 갱신하도록 하는 것을 목적이다.
주체에서 옵저버에게 데이터를 푸시하는 방법과 주체에서 데이터 변경을 알리면 옵저버가 필요한 데이터를 가져가는 풀 방식이 있다.
데이터 전이 방식
푸쉬 방식 | 풀 방식 | |
장점 | 단순성 옵저버는 주제에서 직접 데이터를 전달받기 때문에, 주제의 상태를 쉽게 파악할 수 있다. |
유연성 옵저버가 필요한 데이터만 요청하여 가져올 수 있으므로, 불필요한 데이터 전송을 줄일 수 있다. |
즉시성 데이터가 변경될 때마다 즉시 전달되므로, 옵저버는 항상 최신 상태를 반영한다. |
독립성 주제의 내부 데이터 구조가 변경되더라도 옵저버에는 영향이 적다. 옵저버는 필요한 데이터를 요청하여 가져오기만 하면 된다. |
|
단점 | 과도한 데이터 전달 모든 옵저버에게 모든 데이터를 전달할 필요가 없는 경우에도 데이터를 전달하게 되어 비효율적일 수 있다. |
복잡성 증가 옵저버가 주제의 상태를 가져오기 위해 추가적인 요청을 해야 하므로 코드가 복잡해질 수 있다. |
유연성 부족 주제의 데이터 구조가 변경되면 옵저버도 그에 맞게 변경해야 하는 경우가 발생할 수 있다. |
성능 문제 옵저버가 주제의 상태를 가져오기 위해 여러 번 호출할 경우, 성능 문제가 발생할 수 있다. |
|
의존성 증가 주제와 옵저버 간의 의존성이 커질 수 있다. 주제의 데이터 형식이나 내용이 변경되면 옵저버 코드도 수정해야한다. |
최신성 보장 어려움 옵저버가 주제의 상태를 가져오는 시점에 따라 최신 상태를 반영하지 못할 수 있다. |
- 푸쉬 방식은 간단하고 즉각적인 반응이 필요할 때 유용하지만, 데이터 전달의 효율성 면에서 비효율적일 수 있다.
- 풀 방식은 옵저버와 주제 간의 결합도를 낮추고 유연성을 제공하지만, 코드 복잡성과 성능 면에서 단점이 있다.
구성 요소
- Subject(주체):
- 상태를 가지고 있는 주체 객체.
- 옵저버 객체들을 등록하고, 상태 변경 시 옵저버들에게 알림을 보내는 역할을 한다.
- Observer(옵저버):
- 주체의 상태 변경을 감지하고 그에 따라 동작을 수행하는 객체.
- 여러 개의 옵저버가 주체에 등록되어 있을 수 있다.
- ConcreteSubject(구체적인 주체):
- Subject의 구체적인 구현 클래스로, 상태가 변경될 때마다 등록된 옵저버들에게 알림을 보낸다.
- ConcreteObserver(구체적인 옵저버):
- Observer의 구체적인 구현 클래스로, 주체의 상태 변경에 따라 동작을 수행한다.
예제
// Observer 인터페이스는 옵저버 객체가 업데이트될 때 호출되는 메서드를 정의한다.
public interface Observer {
// 푸시 방식의 update 메서드: 주제에서 전달하는 데이터를 인자로 받는다.
void update(float temp, float humidity, float pressure);
// 풀 방식의 update 메서드: 주제에서 데이터를 직접 가져온다.
void update();
}
// DisplayElement 인터페이스는 화면에 표시하는 기능을 정의한다.
public interface DisplayElement {
// display 메서드는 데이터를 화면에 표시한다.
void display();
}
// Subject 인터페이스는 옵저버를 등록하고 제거하며, 상태가 변경되었을 때 옵저버에게 알리는 메서드를 정의한다.
public interface Subject {
// 옵저버 등록
void registerObserver(Observer observerPush);
// 옵저버 제거
void removeObserver(Observer observerPush);
// 주제의 상태가 변경되었을 때 모든 옵저버에게 변경 내용을 알린다.
void notifyObservers();
}
// WeatherData 클래스는 주제(Subject)를 구현하며, 날씨 데이터를 관리한다.
public class WeatherData implements Subject {
private final List<Observer> observers; // 등록된 옵저버 목록
private float temperature; // 현재 온도
private float humidity; // 현재 습도
private float pressure; // 현재 기압
public WeatherData() {
this.observerPushes = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
// 풀 방식
observer.update();
// 푸시 방식
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 float getTemperature() {
return temperature;
}
// 현재 습도를 반환합니다.
public float getHumidity() {
return humidity;
}
// 현재 기압을 반환합니다.
public float getPressure() {
return pressure;
}
}
// Observer와 DisplayElement 인터페이스를 구현하며, 현재 날씨 상태를 표시한다.
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature; // 현재 온도
private float humidity; // 현재 습도
private final WeatherData weatherData; // WeatherData 객체 참조
// WeatherData 객체를 받아서 자신을 옵저버로 등록한다.
public CurrentConditionsDisplay(WeatherData weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void display() {
System.out.printf("현재 상태: 온도 %fF, 습도 %f%%", temperature, humidity);
}
// 푸시 방식의 업데이트 메서드: 주제에서 데이터를 받아서 필드를 업데이트하고 화면에 표시한다.
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
// 풀 방식의 업데이트 메서드: 주제에서 데이터를 직접 가져와서 필드를 업데이트하고 화면에 표시한다.
@Override
public void update() {
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
728x90
'디자인 패턴' 카테고리의 다른 글
Singletone Pattern (0) | 2024.06.15 |
---|---|
Proxy Pattern (0) | 2024.06.15 |
Mediator Pattern (0) | 2024.05.28 |
Iterator Pattern (0) | 2024.05.27 |
Flyweight Pattern (0) | 2024.05.25 |