Ch.2 옵저버 패턴

객체들에게 연락 돌리기

About

Weather-O-Rama라는 기상 모니터링 애플리케이션 예제를 갖고 옵저버 패턴을 분석한다.

습도 센서, 온도 센서, 기압 센서 등 다양한 센서로부터 기상 정보를 수집하는 기상 스테이션, 기상 스테이션으로부터 오는 정보를 추적하는 WeatherData 객체, 사용자에게 현재 기상 조건을 보여주는 디스플레이 장비 3가지 요소로 구성된다.

The Code

Structure

옵저버 패턴을 구현하는 데에는 여러 방식이 있지만 주로 주제(Subject)와 옵저버(Observer) 클래스 인터페이스로 구성된 옵저버 패턴을 사용한다.

  • 옵저버 패턴에서는 주제가 상태를 저장하고 제어한다. 따라서 상태가 들어있는 객체는 하나만 있을 수 있고, 옵저버는 상태를 사용하지만 소유할 필요는 없으므로 여러 개가 존재할 수 있다. 따라서 하나의 주제에 대해 여러 옵저버가 존재하는 일대다 관계(one-to-many)가 성립한다.

  • 옵저버 패턴을 이용하면 여러 객체가 동일한 데이터를 제어하는 것보다 더 깔끔한 객체지향 디자인을 만들 수 있다.

  • 출판-구독(Publish-Subscribe) 패턴이라는 것도 있는데 이는 관계는 있지만 다른 패턴이다. 출판-구독 패턴의 경우 구독자가 서로 다른 유형의 메시지에 관심을 가질 수 있고, 출판사와 구독자를 더 세세하게 분리할 수 있는 복잡한 패턴이다. 미들웨어 시스템에서 종종 쓰인다.

Loose Coupling

느슨한 결합(Loose Coupling)은 객체들이 상호작용할 수는 있지만, 서로를 잘 모르는 관계를 의미한다.

  • 느슨한 결합을 이용하면 유연성이 좋아진다.

  • 옵저버 패턴은 느슨한 결합을 보여주는 훌륭한 예이다.

    • 주제(Subject)는 특정 인터페이스(Observer)를 구현한다는 사실만 안다. 구체적인 건 알 필요가 없다.

    • 옵저버는 언제든지 새로 추가할 수 있다.

    • 새로운 형식의 옵저버를 추가할 때도 주제를 변경할 필요가 전혀 없다.

    • 주제와 옵저버는 서로 독립적으로 재사용할 수 있다.

    • 주제나 옵저버가 달라져도 서로에게 영향을 미치지는 않는다.

Examples

  • 자바빈(JavaBean)

  • 스윙(Swing) 라이브러리

Notes

  • 자바에는 옵저버 패턴을 위한 Observable 클래스(Subject 클래스)와 Observer 인터페이스가 있었다. 이 클래스들은 자바 9 이후부터 쓰이지 않는다. 각자 자신의 코드에서 기본적인 옵저버 패턴을 지원하는 게 더 편하고 더 강력한 기능을 스스로 구현하는 게 낫겠다고 생각하는 사람들이 늘어서 ObservableObserver는 역사의 뒤안길로 사라졌다.

  • 그를 대신할 만한 기능이 새로 탑재되긴 했다. 자바빈은 Bean에서 PropertyChangeEvents로 유형 속성이 바뀌었을 때 PropertyChangeListener에 알림을 보내 주는 기능을 제공한다. 또한 비동기 스트림(asynchronous stream)을 처리하는 Flow API와 관련된 출판-구독 구성 요소도 제공한다.

Push v.s. Pull for Subject <-> Observer

  • Subject -> Observer로 데이터를 보내는 푸시(push) 방식

  • Subject <- Observer에서부터 데이터를 당겨 오는 풀(pull) 방식

이 있다. 푸시보단 데이터를 당겨 오는 풀이 더 바람직하다. 나중에 새로운 옵저버를 추가하기 쉬운, 확장이 용이한 디자인이기 때문이다.

Summary

  • 옵저버 패턴은 객체들 사이에 1:N 관계를 정의한다.

  • 주제(Subject)는 동일한 인터페이스를 사용해 옵저버(Observer)에게 연락한다.

  • Observer 인터페이스를 구현하기만 하면 어떤 클래스의 옵저버라도 패턴에 참여할 수 있다.

  • 주제는 옵저버들이 Observer 인터페이스를 구현한다는 것을 제외하면 옵저버에 관해 전혀 모른다. 따라서 이들 사이의 결합은 느슨한 결합이다.

  • 옵저버 패턴을 사용하면 주제가 데이터를 보내거나(Push 방식) 옵저버가 데이터를 가져올(Pull 방식) 수 있다.

    • 일반적으로 Pull 방식이 더 '옳은' 방식이라고 간주한다.

  • Swing은 다른 여러 GUI 프레임워크와 마찬가지로 옵저버 패턴을 많이 사용한다.

  • RxJava, 자바빈, RMI 외에 코코아, 스위프트, 자바스크립트와 같은 다른 언어의 프레임워크에서도 옵저버 패턴을 많이 사용한다.

  • 옵저버 패턴은 여러 개의 주제와 메시지 유형이 있는 복잡한 상황에서 사용하는 출판-구독 패턴(Pub-Sub Pattern)과 친척이다.

  • 옵저버 패턴은 자주 쓰이는 패턴으로 모델-뷰-컨트롤러(MVC)를 배울 때 다시 만날 수 있다.

My Thoughts

  • 옵저버 패턴... 많이 흥미로운 패턴인 것 같다. 코드를 뜯어보기 전까지는 어떻게 동작하는지 이해하기 어려운데 막상 보면 고개를 끄덕이게 되는 프로그래밍의 마법 같은 부분이라고 생각한다.

  • 옵저버 패턴이 MVC에도 적용되는 줄은 몰랐다.

Last updated