개요
옵저버 패턴에 대한 이해.
설명
위키를 기준으로 설명.
- 객체의 상태변화를 관찰하는 옵저버들을 객체에 등록하여, 객체에 대한 상태변화가 있을때마다 각각의 옵저버들에게 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 서적을 추천해준다.
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() 가 두 번 이상 호출되는 것을 막으려고 하였다.
하지만 주석에서 보는 것처럼 두 가지의 최악의 상황을 생각해볼 수 있다고 한다.
- 새롭게 추가되는 Observer 는 진행 중인 notification 에 대해서 update 를 수행하지 못한다.
- 스레드 A 에서 notifyObservers 를 수행시키고 있을 시에, 스레드 B 에서 동일 객체에 대해서 새로운 Observer 를 등록하고 있다면 arrLocal 에 할당한 Observer 에는 스레드 B 에 등록한 새로운 옵저버가 존재하지 않을 경우가 크다.
- 최근에 등록 해지를 수행한 Observer 가 의도치 않게 notified 될 수 있다.
- 다수의 스레드 환경을 고려하면 가능성이 있다.
왜 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 이다.
참고링크
'프로그래밍 언어' 카테고리의 다른 글
20191213 DDD 에서 사용하는 표현 및 용어 정리. (0) | 2019.12.13 |
---|---|
20190427 스트래티지 패턴 (Strategy Pattern) (0) | 2019.04.27 |
20180208 싱글톤, Singleton (수정 20190619) (0) | 2018.02.08 |
20180129 Loose Coupling & High Cohesion 2 (0) | 2018.01.29 |
20180128 Loose Coupling & High Cohesion (0) | 2018.01.28 |