4. Observer Pattern (옵저버 패턴)
Publish/Subscriber Model이라고도 불리는 Observer Pattern에 대해 알아보자.
1. Purpose
Lets one or more objects be notified of state changes in other objects within the system.
어떤 객체의 소식을 하나 이상의 객체에서 변화때 마다 전달받기 위해
2. Use When
- Loose coupling is needed for communications
- State changes in one or more objects should trigger behavior in other objects
- Broadcasting capabilities are required
- An understanding exists that objects will be blind to the expense of notification
예시를 통해 알아보자
Weather Station에서 습도, 기온, 압력을 측정하여 정보를 갖고있고 이를 여러 가지방법으로 Display하여 주려고한다. 이때 현재 WeatherData에 따라 Display가 항상 갱신되기 원할때 Concrete한 방법으로는 측정 값들의 변화 아래 모든 Display에 대해 update를 해주는 방법이있다.
하지만 이런 방식의 구현은 새로운 Display에 따라 코드의 수정이 빈번히 일어나게된다는 단점이 있다. Observer Pattern은 Subscribe(구독)를 통해 Publisher의 변화에 따라 자동으로 소식을 update받는 패턴이다. 이때 데이터를 제공해주는 객체를 Publisher 혹은 Subject라고 부르며 데이터를 받는 객체를 Subscriber 또는 Observer라고 부른다.
기본적인 Observer Pattern 의 구조는 이렇다. Subject는 멤버변수로 Interface Observer를 갖는다. 리스트 형식으로 갖고있으며 Observer에게 register, remove와 같이 구독과 구독해제에 대한 API를 제공한다. Observer는 update라는 API를 갖고있으며 Subject가 상태가 변경되어 Observer들에게 notify할때 이 API를 이용한다.
인터페이스로 Subject와 Observer를 만들고 이를 상속하는 ConcreteSubject와 ConcreteObserver를 만든것이 특이할 수 있는데 이는 Coupling을 최소화 해주기 위함이다. 정보 제공자는 자신을 구독하는 Observer에 대해 알지않아도 된다. 단지 그 객체가 Observer Interface를 따른다는 것만 알고있다. 멤버변수로 갖고있는 Observer 리스트에 대해 자신의 상태가 변화하면 notify함수에서 리스트로 가지고있는 Observer.update만을 수행시켜주면 된다. 얻어온 정보를 어떻게 사용하는지는 각각의 ConcreteObserver에서 수행한다.
ConcreteSubject는 위와 같이 완성된다. Observer에게 제공되는 register, remove Observer에서는 리스트에 Observer를 추가 혹은 제거한다. setMeasurement로 값들을 변경시키면 측정값이 변화하였기 때문에 measurementChanged()를 통해 notifyObserver함수가 실행된다. 이때 구독하고있는 Observer들을 update시켜주어 소식을 알려준다.
Observer Pattern을 적용한 WeatherData의 구조는 이러하다.
실제 Observer Pattern은 Java에서 Observable과 Observer클래스로 지원하고 있으며 단순히 이를 상속하여서 사용할 수 있다. 이때 주의할 점은 Observable 클래스가 abstract class인것이다. 즉, ConcreteObservable클래스를 만들때 단일상속만 가능하기 때문에 두개이상의 클래스를 상속해야만 하는경우 직접 구현해야한다.
위 클래스 다이어그램을 보면 Observable클래스에는 등록과 삭제, 알림외에 setChanged라는 함수가 존재한다. 이 함수는 notify전에 꼭 호출되어야 한다. 왜 굳이 저런 함수를 두어 Observer에게 알릴때 두개의 함수를 호출하도록 할까라는 의문이 들수 있겠지만 setChanged는 통신의 오버헤드를 조절하는 역할을 한다. 예를 들어 현재온도를 계속해서 Observer에게 보여주고 싶다고하자. 측정값이 0.001도만 변화하여도 변화한것이다. 하지만 이런 사소한 변화가 일어날 때 마다 Observer에게 알려주는 행위는 부담이 될 수 있다. 임계값을 정해 그 이상의 변화에서 setChanged를 수행해주면 그때 Observer에게 변화를 알려주게된다.
지금까지 Observer Pattern에 대해 알아보았다. 이 패턴은 상호작용하는 두 객체사이의 관계를 최소화 하며 통신할 수 있도록 하며 코드의 재사용성, 다양한 Publisher를 둘 수 있다는 장점이있다.