Duplicate

옵저버 패턴이란 무엇인가? - 디자인 패턴

태그
Design Pattern
observer
구독
공개여부
작성일자
2021/01/06
이 내용은 Head First 의 옵저버 패턴 챕터를 읽고 작성한 글 입니다.
제가 작성한 코드는 저의 깃헙에서 확인할 수 있습니다!

WeatherData 클래스를 열어봅시다.

요구사항
class WeatherData { getTemperature(); getHumidity(); getPressure(); measurementsChanged(); }
Java
1.
WeatherData 클래스에 온도, 습도, 기압을 알아내기 위한 getter 메소드가 있다.
2.
새로운 측정 데이터가 나올 때 마다 measurementsChaged() 메소드가 호출된다.
3.
기상 데이터를 사용하는 3개의 display 항목을 구현해야 한다.
4.
시스템 확장이 가능해야 한다. 다른 개발자들이 별도의 display 항목을 만들 수 있도록 해야 하고 사용자들이 애플리케이션에 마음대로 항목을 추가/제거 할 수 있도록 해야한다.
옵저버 패턴 → 출판사(subject) + 구독자(observer)

옵저버 패턴의 정의

정의: 한 object 의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로 갱신되는 방식으로 1:N 의존성을 정의한다.
subject 는 상태를 가지고 있다.
observer 는 의존성을 갖는다.
단 subject 가 갱신해주기를 기다려야 한다.
신문사가 신문을 발행하고 구독자가 그 신문을 구독하는 프로세스와 비슷하다 → 구독, 구독 취소, 발행 등등

느슨한 결합(Loose coupling 의 위력)

→ 느슨한 결합: 상호작용은 하는데 서로 잘 모르는 사이이다.
subejct 가 가진 정보는 observer interface 를 구현한 것 뿐이다.
Observer interface 를 구현만 하면 되니 추가, 교체, 동적 변경이 가능하다 (SOLID 의 OCP 원칙)
observer 가 변경된다고 해서 subject 가 바뀔 필요가 없다.
독립적인 재사용 → 다른 용도로 써도 된다.
서로 interface 를 알기 때문에 나머지가 바뀌어도 문제 없다.
💡
디자인의 원칙 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다.

기상 스테이션의 설계

기상 스테이션의 구현

자바에서 observer 패턴의 일부를 지원하지만 많은 경우에 직접 구현하는 것이 더 낫다.
public interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers(); }
Java
/** * 모든 observer class 는 이 interface 를 구현해야 한다. */ public interface Observer { void update(float temp, float humidity, float pressure); }
Java
public interface DisplayElement { void display(); }
Java

WeatherData 에서 subject interface 구현

public class WeatherData implements Subject { public WeatherData() { observers = new ArrayList<>(); } private List<Observer> observers; private float temperature; private float humidity; private float pressure; @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { int index = observers.indexOf(o); if (index >= 0) { observers.remove(o); } } /** * 상태를 모든 observer 들에게 알려주는 역할을 한다. */ @Override public void notifyObservers() { observers.stream() .forEach(observer -> observer.update(temperature, humidity, pressure)); } public void measurementsChanged() { notifyObservers(); } /** * 데이터를 받는곳, 데이터를 받으면 상태를 변경하고 모든 observer 에게 알려준다 * @param temp * @param humidity * @param pressure */ public void setMeasurements(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
Java
스프링에 사용한다면 bean 에 적합하지 않을까 싶기도 함.

디스플레이 항목

현재 기상 조건을 표시하는 display
public class CurrentConditionDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionDisplay(Subject subject) { this.weatherData = subject; weatherData.registerObserver(this); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } @Override public void display() { System.out.println("Current condition: " + temperature + "F degrees and " + humidity + "% humidity"); } }
Java
@Test @DisplayName("만들어둔 subject, observer 의 디스플레이 장치가 잘 동작하는지 확인해보자") void printWeatherData() { WeatherData weatherData = new WeatherData(); CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData); StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); weatherData.setMeasurements(80, 65, 30.4f); weatherData.setMeasurements(82, 70, 29.2f); weatherData.setMeasurements(78, 90, 29.2f); }
Java
1.
observer 와 subject는 서로에 대해 잘 모른다
2.
갱신이 발생하면 subject 는 observer 에게 알려주고, observer 는 subject에 변경이 발생함을 인식한다.
3.
갱신이 발생할 때 observer 는 갱신에 알맞은 로직을 수행한다.
4.
subject 는 자신의 상태(state)를 observer 에게 알려주지 않는다

java 가 제공하는 Observer

java9 부터 deprecated 되었으니 간단히 알아본다.
Observable 확인
Observer 확인
Observable : subject 역할을 수행한다
Observer: 옵저버 역할을 수행한다.
subject 의 가장 큰 차이점은 직접 구현했던 registerObserver(Observer o)addObserver,
removeObserver(Observer o)deleteObserver 로 변경되고 setChange 라는 함수를 통해 subject 에 갱신을 일으켜야 한다.
observer 는 비슷하게 update 를 사용한다.
update(Observable o, Object arg);
Java

주의할 점

Observable 에서 observer 로 보내는 알림은 순서가 보장되지 않는다.
하지만 순서가 보장된다면 느슨한 결합이라 할 수 없다.
Observable 은 클래스 이다.
서브 클래스를 만들어야 한다 (오브젝트에서 이 문제점은 다루었으니 생략한다)
인터페이스가 없기 때문에 Observer API 와 잘 맞는 클래스를 구현하기 불가능하다
java.util 의 구현을 다른 구현으로 바꾸는 것이 불가능하기 때문에 multi thread 로 구현하는 것은 불가능하다.
클래스의 핵심 메소드를 외부에서 호출할 수 없다.
setChanged() 는 protected 로 선언되어 있다.
서브 클래스를 인스턴스 변수로 사용할 수 없게 된다(그냥 상속을 사용해야함)
물론 위의 문제는 Observable 을 직접 구현해서 필요한 함수들을 overriding 한다면 해결이 된다.
중요한 것은 Observer pattern 이 무엇이고 어떻게 써야하는지를 명확히 이해했다면 그 패턴을 사용한 API 를 얼마든지 구현할 수 있다.
Made with 💕 and Oopy
TOP