이 글은 Patterns.dev 사이트를 참고하여 작성한 시리즈 입니다.
Observer Pattern
옵저버블을 사용해 이벤트가 발생할 때 구독자에게 알리기
옵저버 패턴을 사용하면 특정 객체(object)나 옵저버(observer)를 옵저버블(observable)이라 불리는 다른 객체를 구독(subscribe)할 수 있습니다.
observable 객체는 일반적으로 3가지 중요한 요소를 포함합니다.
- observers: 특정 이벤트가 발생할 때마다 알림을 받는 observer 배열
- subscribe(): observers에 observer를 추가하는 메소드
- unsubscribe(): observers에서 observer를 삭제하는 메소드
- notify(): 특정 이벤트가 발생할 때마다 모든 observer에게 알리는 방식
Observable 만들기
ES6의 class를 사용하면 쉽게 만들 수 있습니다.
subscribe 메소드로 observers에 옵저버를 추가하고 unsubscribe 메소드로 옵저버를 제거하며, notify 메소드로 모든 구독자에게 payload를 전달할 수 있게 되었습니다.
Observable 사용하기
옵저버블을 사용해 봅시다.
아래 코드는 Button과 Switch 컴포넌트를 갖고 있는 기본적인 어플리케이션입니다.
우리는 어플리케이션과 사용자의 상호작용을 추적하고 싶습니다. 사용자가 버튼을 클릭하거나(event) 스위치를 전환할 때(event)마다 이 이벤트를 타임스탬프와 함께 기록하고 표시되는 토스트 알림도 만들고 싶습니다.
최종적으로 만들고자 하는 형태는 다음과 같습니다.
사용자가 handleClick 이나 handleToggle을 호출할 때마다 observer에 있는 notify 메소드를 호출시킵니다. notify 메소드는 모든 subscriber에 의해 handleClick이나 handleToggle에서 전달된 data(payload)를 통지합니다.
먼저 logger와 toadtify 함수를 작성하겠습니다. 이 함수들은 최종적으로 notify 메소드에서 data(payload)를 전달받습니다.
현재는 옵저버블이 logger와 toastify를인지하지 못합니다. 옵저버가 되도록 하려면 이 함수들을 옵저버블에 subscribe 메소드를 사용하여 등록해야합니다.
이제 이벤트가 발생할 때마다 logger와 toatify 함수가 실행됩니다. 이제 옵저버블의 notify를 호출할 핸들러 함수만 구현하면 됩니다.
함수의 이름은 handleClick, handleToggle로 하겠습니다. 그리고 함수에 옵저버가 수신해야할 데이터를 함께 넘겨줍니다.
이제 전체 흐름을 완성했습니다. handleClick() 이나 handleToggle()을 호출하면 notify를 통해 logger()와 toastify()를 호출하게 됩니다.
옵저버 패턴은 여러 가지 방법으로 사용할 수 있지만 비동기 이벤트기반 데이터를 사용할 때 매우 유용합니다. 특정 데이터가 다운로드 완료될 때 또는 사용자가 메세지 보드에 알림을 보내고 다른 사용자들이 알림을 받을 수 있습니다.
사례
Observable을 사용하는 일반적인 라이브러리는 RxJS입니다.
ReactiveX는 옵저버 패턴과 이터레이터 패턴을 함수형 프로그래밍과 컬렉션을 결합하여 이벤트 시퀀스를 관리하는 이상적인 방법을 제공합니다.
RxJS로 옵저버블을 생성하고 일부 이벤트들을 subscribe 해보겠습니다. 다음 예시는 사용자가 화면을 드래그 했는지 여부를 console.log를 통해 표시합니다.
장점
옵저버 패턴은 관심사 분리와 단일 책임 원칙을 강제할 수 있는 좋은 방법입니다. 옵저버는 옵저버블과 긴밀하게 결합되지 않으며 언제든지 합치거나 분리할 수 있습니다. 옵저버블은 이벤트를 모니터링 하는 역할을 하며 옵저버는 수신된 데이터를 처리합니다.
단점
옵저버가 너무 복잡해지면 모든 구독자에게 통지할 때 퍼포먼스 문제가 발생할 수 있습니다.
Reference
'Web > Patterns' 카테고리의 다른 글
Proxy Pattern (JavaScript) (0) | 2022.06.07 |
---|---|
Singleton Pattern (JavaScript) (0) | 2022.06.07 |