📍 옵저버 패턴(Observer Pattern) : 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의함.
주제와 옵저버로 일대다 관계가 정의됨.
옵저버는 주제에 딸려있음.
옵저버 패턴의 경우, 보통 주제 인터페이스와 옵저버 인터페이스가 들어있는 클래스 디자인으로 구현됨.
옵저버 패턴의 구조
주제를 나타내는 Subject 인터페이스
각 주제마다 여러개의 옵저버가 있을 수 있음.
옵저버가 될 가능성이 있는 객체는 Observer 인터페이스를 구현해야 함.
update() 메소드를 구현해야 함.
주체 상태가 바뀌면 해당 메소드를 호출함.
주제 역할을 하는 구상 클래스는 Subject 인터페이스를 구현해야 함.
느슨한 결합의 위력
느슨한 결합 : 객체들이 상호작용할 수는 있지만, 서로를 잘 모르는 관계임.
유연성이 아주 좋아짐.
옵저버 패턴이 느슨한 결합을 보여주는 훌륭한 예임.
주제는 옵저버가 특정 인터페이스(Observer 인터페이스)를 구현한다는 사실만 암.
옵저버는 언제든지 새로 추가할 수 있음.
새로운 형식의 옵저버를 추가할 때도 주제를 변경할 필요가 전혀 없음.
주제와 옵저버는 서로 독립적으로 재사용할 수 있음.
주제나 옵저버가 달라져도 서로에게 영향을 미치지 않음.
📍 디자인 원칙 : 상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다. 느슨하게 결합하면, 변경 사항이 생겨도, 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있음. 왜냐면 객체 사이의 상호 의존성을 최소화하기 때문
기상 스테이션 구현하기
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 humidity, float pressure);
}
public interface DisplayElement {
public void display();
}
주제는 옵저버를 등록하고, 제거하는 역할을 가져야 함.
주제 상태가 변경되면 모든 옵저버에게 변경 내용을 알리는 메소드를 구현해야 함.
옵저버의 update 메소드인자는 기상 정보가 변경될 때 옵저버에게 전달되는 상태값임.
Subject 인터페이스 구현하기
public class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<Observer>();
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer observer : observers) {
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();
}
// 기타 WeatherData 메소드
}
WeatherData 는 주제의 구상 클래스임.
온도, 습도, 기압과 옵저버 객체들을 가지고 있음.
기상 스테이션에서 가상 데이터를 가져올 때, setMeasurements 메서드가 호출됨.
그러면 새로운 측정 값이 갱신되고, 모든 옵저버에 notify 함.
디스플레이 요소 구현하기
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 void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}
옵저버 구상 클래스는 Observer 를 반드시 구현해야 함.
update가 호출되면 온도와 습도를 저장하고, display를 호출함.
update 메소드에 display 메소드를 호출하는 방법은 지금과 같이 간단한 경우에는 괜찮아 보임.