일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 네이버 부캠
- 부스트캠프
- 비디오 스트리밍
- 씨쁠쁠
- beautifulsoup
- 스택
- 자바스크립트
- 코딩테스트
- react
- 자바스크립트 객체
- Image 컴포넌트
- 프로그래머스
- PubSub 패턴
- Next.js
- c++
- 자바 프로젝트
- Server Side Rendering
- 웹크롤링
- 파이썬 웹크롤링
- Next/Image 캐싱
- 파이썬
- 멘션 추천 기능
- 네이버 부스트캠프
- 브라우저 동작
- 네이버 부스트캠프 멤버십
- 자바스크립트 컴파일
- 파이썬 코딩테스트
- React ssr
- git checkout
- React.js
Archives
- Today
- Total
코린이의 개발 일지
Observer 패턴 살펴보기 본문
반응형
Observer pattern
- 객체의 상태 변화를 관찰하는 옵저버들의 목록을 객체에 등록하여, 상태 변화가 있을 때마다 notify를 통해 객체가 직접 목록의 각 옵저버에게 통지하도록하는 디자인 패턴
구현 예시
- 기본적인 인터페이스는 아래와 같다.
Subject
class Subject {
#state;
constructor() {
this._observers = new Set();
}
subscribe(observer) {
this._observers.add(observer);
}
unsubscribe(observer) {
this._observers.delete(observer);
}
notify() {
this._observers.forEach((observer) => observer.update(this.#state));
}
}
Observer
class Observer {
update(newState) {}
}
observer 패턴이 동작하는 방식을 간단히 살펴보면
- Observer들은 notify가 발생했을 때, 할 행동을 정의한다 (update)
- Subject는 자신을 구독하는 구독자들(Observer들)을 관리하는 메소드를 정의한다.
- 구독
- 구독 취소
- 이벤트 발생
- 이때 핵심은 Subject에서 notify할때, Observer의 메소드를 직접 호출한다는 것이다.
- 이부분이 Pubsub 패턴과의 차이점인데, Observer 패턴은 Observer와 Subject가 서로 인지하고 있고, Subject가 Observer에 직접 알려준다. (따라서 pubsub 패턴보다 Observer 패턴이 더 결합도가 높다)
직접 구현하고 실행해보자
위의 클래스를 상속받아와서 구현한다.
예시 Observer
class ObserverA extends Observer {
state;
update(newState) {
this.state = newState;
console.log("A update to", this.state);
}
display() {
console.log("Observer A:", this.state);
}
}
class ObserverB extends Observer {
state;
update(newState) {
this.state = newState * 2;
console.log("B update to", this.state);
}
display() {
console.log("Observer B:", this.state);
}
}
예시 Subjects
class UpdateSubject extends Subject {
setState(newState) {
this.state = newState;
this.notify();
}
getState() {
return this.state;
}
}
사용 코드
const obsA = new ObserverA();
const obsB = new ObserverB();
const update = new UpdateSubject();
update.subscribe(obsA);
update.subscribe(obsB);
update.setState(3);
/*
출력 결과
A update to 3
B update to 6
*/
그렇다면 만약, update 이벤트 발행이 아닌, display 이벤트를 발행하고 싶다면 어떻게 해야할까?
아래와 같은 클래스를 하나 더 정의 해주어야한다.
class DisplaySubject extends Subject {
notify() {
this._observers.forEach((observer) => observer.display());
}
getState() {
return this.state;
}
}
사용코드
const obsA = new ObserverA();
const obsB = new ObserverB();
const display = new DisplaySubject();
const update = new UpdateSubject();
update.subscribe(obsA);
update.subscribe(obsB);
display.subscribe(obsA);
update.setState(3);
display.notify();
/*
출력 결과
A update to 3
B update to 6
Observer A: 3
*/
PubSub패턴으로 바꿔보기
위와 같은 동작을 PubSub으로 바꾸어보자.
PubSub
class PubSub {
constructor() {
this.events = new Map();
}
subscribe(eventType, func) {
if (!this.events.has(eventType)) {
this.events.set(eventType, []);
}
const funcs = this.events.get(eventType);
funcs.push(func);
this.events.set(eventType, funcs);
}
publish(eventType, ...args) {
const funcs = this.events.get(eventType);
funcs.forEach((func) => func.apply(null, args));
}
}
Publisher
class Publisher {
constructor(topic) {
this.topic = topic;
}
}
class UpdatePublisher extends Publisher {
publish(newState) {
ContentServer.publish(this.topic, newState);
}
}
class DisplayPublisher extends Publisher {
publish() {
ContentServer.publish(this.topic);
}
}
Subscriber
class Subscriber {
subscribe(topic) {}
update(newState) {}
}
class SubscriberA extends Subscriber {
state;
subscribe(topic) {
switch (topic) {
case "update":
ContentServer.subscribe(topic, this.update.bind(this));
break;
default:
ContentServer.subscribe(topic, this.display.bind(this));
}
}
update(newState) {
this.state = newState;
console.log("A update to", this.state);
}
display() {
console.log("Subscriber A:", this.state);
}
}
class SubscriberB extends Subscriber {
state;
subscribe(topic) {
switch (topic) {
case "update":
ContentServer.subscribe(topic, this.update.bind(this));
break;
default:
ContentServer.subscribe(topic, this.display.bind(this));
}
}
update(newState) {
this.state = newState * 2;
console.log("B update to", this.state);
}
display() {
console.log("Subscriber B:", this.state);
}
}
사용 코드
const ContentServer = new PubSub();
const subA = new SubscriberA();
const subB = new SubscriberB();
const display = new DisplayPublisher("display");
const update = new UpdatePublisher("update");
subA.subscribe("update");
subA.subscribe("display");
subB.subscribe("display");
update.publish(4);
display.publish();
/*
출력 결과
A update to 4
Subscriber A: 4
Subscriber B: undefined
*/
- Observer 패턴에서와 다르게, Publisher와 Subscriber가 전혀 접점이 없다.
- PubSub이라는 일종의 broker를 통해 Publisher와 Subscriber가 연결 되어 있기 때문에, Publisher가 Subscriber의 위치나 존재를 알 필요없이 Message Queue와 같은 Broker역활을 하는 중간지점에 메시지를 던져 놓기만 하면 된다.
- 반대로 Subscriber 역시 Publisher의 위치나 존재를 알 필요없이 Broker에 할당된 작업만 모니터링하다 할당 받아 작업하면 되기 때문에 Publisher와 Subscriber가 서로 알 필요가 없다.
최종 정리
- Observer 패턴이란 객체의 상태 변화를 관찰하는 옵저버들의 목록을 객체에 등록하여, 상태 변화가 있을 때마다 notify를 통해 객체가 직접 목록의 각 옵저버에게 통지하도록하는 디자인 패턴이다.
- Observer 패턴과 Pub-Sub 패턴의 차이점
- 가장 큰 차이점은 중간에 Message Broker혹은 Event Bus가 존재하는지 여부이다.
- Observer 패턴의 경우 Subject에 Observer를 등록하고 Subject가 notify를 통해 직접 Observer에 알려주어야 한다.
- Observer 패턴이 더 결합도가 높다.
반응형
Comments