개요

옵저버 패턴에 대한 이해.

 

설명

위키를 기준으로 설명.

  • 객체의 상태변화를 관찰하는 옵저버들을 객체에 등록하여, 객체에 대한 상태변화가 있을때마다 각각의 옵저버들에게 notify 해주는 디자인패턴이다.

위키에 있는 그림 그래도이다.

  • Subject 는 정의된 특정 객체이다.
  • Subject 에 어떤 변화가 상태의 변화가 감지되면, notifyObservers() 메소드를 통해서 현재 객체에 등록된 옵저버들에게 notify() 메소드를 수행한다. 따라서, 해당 옵저버는 각각의 옵저버 특성에 맞는 행동을 수행한다.
  • Subject 에는 register/unregister 가 있는데 새로운 옵저버를 등록하거나 미리 등록된 옵저버를 해제하는 등의 메소드를 수행하여 이벤트가 지속적으로 발생하여 무분별하게 notify 를 되는 것을 제어할 수 있다.
  • 발행/구독 모델이라고도 칭한다. 흔히 말하는 pub/sub 이벤트 구조
    • 문득 글을 읽다가 aws sns 가 생각났다. 고도화 및 추상화된 서비스들의 기반은 디자인 패턴인 것 같다.

 

현재 자바 API 단에서 살펴보면 Observer 인터페이스 및 Observable 클래스는 사전에 정의되어있다. (비록 @Deprecated 되었지만, Java9 까지 사용이 가능한 상태이다.)

 

Obseravble class

해당 클래스는 특정한 클래스는 지칭한다. 위의 다이어그램상 Subject 를 의미.

 

 

Observer interface

해당 클래스는 옵저버 클래스인데, 구현체가 따로 필요하고 update 메소드가 재정의되어야 한다.

 

observable 과 observer 는 1:N 관계로 설정되어있다.

왜 1:N 관계로 설정되는가에 대해서 스택오버플로우 링크에서 설명해주고 있다.

  • 신문과 신문을 구독하는 사람들로 예시를 들어 설명해준다.
  • 트위터와 팔로워 예시를 들어 설명해준다.
  • 링크를 살피면 누군가 댓글에 에릭 에반스의 DDD 서적을 추천해준다.

Observable 클래스에 대한 주석

 But from a basic subject-observer context 
 in observer design pattern implementation the Subject does not care.

 

 

최초에 Observable 클래스가 생성되면 0 개의 observers 가 생성된다. 그리고 Observable 에 있는 클래스의 addObserver() 와 deleteObserver() 메소드를 통해서 옵저버를 추가 및 삭제한다.

 

1. 상태가 변경이 되면, setChanged() 메소드를 통해 해당 객체가 변경되었음을 설정한다.

 

2. 객체가 변경되었음을 hasChanged() 를 통해 확인한다. 

 

3. 객체가 가진 옵저버들에게 객체의 상태가 변경되었음을 알리기 위해 update() 메소드를 호출한다.

멀티 스레드 환경에서 다수의 스레드가 동일 Observavble 클래스에 대해서 notifyObservers() 를 호출하는 것을 막기 위해서 sychronized() 를 사용하여 동기화시켰다. 해당 블록 내에서 동기화된 스레드의 접근을 설정해서 update() 가 두 번 이상 호출되는 것을 막으려고 하였다.

 

하지만 주석에서 보는 것처럼 두 가지의 최악의 상황을 생각해볼 수 있다고 한다.

  1. 새롭게 추가되는 Observer 는 진행 중인 notification 에 대해서 update 를 수행하지 못한다.
    1. 스레드 A 에서 notifyObservers 를 수행시키고 있을 시에, 스레드 B 에서 동일 객체에 대해서 새로운 Observer 를 등록하고 있다면 arrLocal 에 할당한 Observer 에는 스레드 B 에 등록한 새로운 옵저버가 존재하지 않을 경우가 크다.
  2. 최근에 등록 해지를 수행한 Observer 가 의도치 않게 notified 될 수 있다.
    1. 다수의 스레드 환경을 고려하면 가능성이 있다.

 

왜 Observable 과 Observer 는 java 9 이후부터 @Deprecated 가 되었는가?

  • 제한적인 이벤트 모델
    • 완료의 개념이 존재하지 않는다. Complete 가 되었으면 complete 가 되었다고 전달이 필요하다.
    • 에러 핸들링에 대한 명시가 따로 존재하지 않는다.
  • 보장되지 않은 알림 순서
  • 상태에 대한 변경은 1:1 대응이 아니다.
    • 아마 멀티스레드 환경에서의 상태가 변경된 상태에서 nofity 를 수행하는 찰나에 한번 더 notify 가 수행될 시에 1:1 로 호출 및 응답이 안된다는 걸 말하는 듯 하다. 
  • 애플리케이션을 위한 풍부한 모델을 지원 미존재 (= 제한적인 이벤트 모델과 비슷한 맥락읙 구문)
  • 스레드에 대한 신뢰성있는 순서를 보장받기 위해선 동시성 데이터 구조를 고려 (ex. java.util.concurrent 패키지 참고)
  • 리액티브 스타일의 프로그래밍을 하기 위해선 java.util.concurrent.Flow 클래스 참고

 

정리

  • 옵저버 패턴은 pub/sub 형태
  • pub 을 통해 여러 subscriber 에게 멀티캐스트가 가능하다.
  • pull 과는 상대적인 push 이다.

 

참고링크

Posted by doubler
,