-
[Design Pattern] Observer PatternLearn/Architecture 2022. 8. 27. 22:55
# 개요
한 쪽의 오브젝트가 변화가 있을 때, 다른 오브젝트들이 노티아야 할 때 사용하는 패턴
Observer Pattern은 아래와 같은 상황을 해결하기 위해 사용된다.
아래의 예시에서 WeatherData는 WeatherStation으로부터 날씨 데이터를 받아서 Device에 전달한다.
WeatherStation으로부터 날씨 변화를 받기 위해서는 아래 구조에서 measurementChanged 부분을 구현해야 한다.
> 날씨 데이터의 구성 요소가 변하는 것에도 대응할 수 있어야 하고 확장성도 고려해야 한다.
이를 위해 아래와 같이 update함수를 고려해 볼 수 있다.
하지만 변수가 늘어나거나 Display에 변경이 있을 때 마다 매번 코드를 수정해줘야 한다.
public class WeatherData { // instance variable declarations 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); } // other WeatherData methods here }
# Observer Pattern
publish / subscribe 모델이라고도 부른다.
신문사과 신문구독자로 생각하면 이해하기 쉽다.
- 신문사는 구독자에게 새로운 신문이 나올때마다 알려준다.
- 구독을 해지하면 더이상 알려주지 않는다.
클래스 다이어그램으로 표현해보면 다음과 같다.
- Subject (publisher)쪽은 구독신청, 해지, 알림에 대한 API를 제공한다. (ConcreteSubject에서 구현)
- Observer쪽은 update API만 제공하면 된다. (ConcreteObserver에서 구현)
- ConcreteSubject는 ConcreteObserver쪽에 대한 지식이 전혀 없다. (Interface로만 통신하므로)
Observer Pattern은 잘 쓰면 커플링을 줄여준다.
# 구현
Interface
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(); }
ConcreteSubject
- setMeasurements는 테스트를 쉽게 하기위한 helper method
public class WeatherData implements Subject { private ArrayList observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { int i = observers.indexof(o); if(i>=0) observers.remove(i); } public void notifyObservers() { for(int i = 0; i < observers.size(); i++) { Observer observer = (Observer)observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObservers(); } // helper method public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } // other WeathreData methods here }
ConcreteObserver
public class CurrentConditionDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionDisplay(Subject weatherData) { this.weathreData = 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”); } }
# Observable (JAVA)
자바에는 이미 Observable이라는 클래스에 구독, 해지, 노티같은 것들이 이미 구현되어있다.
Interface도 이미 구현되어있다.
Publisher는 노티를 보내기전에 Setchanged 함수를 호출해야 한다.
- 변화가 있을 때마다 노티를 보내면 오버헤드가 크기때문에 이렇게 설계했다. (git의 commit느낌?)
Subscriber는 Observer interface를 구현해야 한다.
- 관심있는 데이터를 publisher의 API로 호출하는 방식 (pull)
import java.util.Observable; import java.util.Observer; public class CurrentConditionsDisplay implements Observer, DisplayElement { Observable observable; private float temperature; private float humidity; public CurrentConditionsDisplay(Observable observable) { this.observable = observerble; observable.addObserver(this); } 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(“Current conditions: ” + temperature + “F degrees and” + humidity + “% humidity”); } }
# QUIZ
Q1. Observer 패턴에서 약한 커플링 (loose coupling)이 어떻게 달성되는지 간략히 설명하시오.
A. 커뮤니케이션에 참여하는 두 객체는 인터페이스로만 소통하므로 서로간에 아는 정보가 적음.
Q2. Observer 패턴을 사용할 때, Publisher 역할을 수행하는 객체가 여러 개 있을 수 있는가?
A. Subscriber들이 pull 방식으로 구독신청을 하는 방식이므로 가능하다. 또한 publisher이면서 동시에 subscriber일 수도 있다.
'Learn > Architecture' 카테고리의 다른 글
[Design Pattern] Iteration Pattern (0) 2022.08.28 [Design Pattern] Template Method Pattern (0) 2022.08.28 [Design Pattern] Strategy Pattern (0) 2022.08.26 [Design Pattern] GRASP Principle (0) 2022.08.24 [Design Pattern] SOLID Principle (0) 2022.08.21