본문 바로가기

공부/TIL

옵저버 패턴 알아보기

반응형

옵저버 패턴이란? 📖

객체의 상태 변화를 관찰하는 옵저버(Observer)들이 있고, 관찰 대상이 되는 객체(Subject)가 상태 변화가 있을 때 옵저버들에게 알리는 디자인 패턴입니다.

 

간단하게 설명하면

  • 어떤 데이터나 상태의 변화가 일어났을 때, 실시간으로 구독자들에게 알려주는 방식

Observer

 

`Subject (주체)` : 상태를 보유하고 있고, 변화가 일어났을 때 옵저버들에게 알리는 역할

`Observer (옵저버)` : 주체의 상태 변화를 감지하고 그에 따라 행동

 

옵저버 패턴 직접 만들어보기 📖

subject.js

const createSubject = () => {
  const observers = new Map();

  const addObserver = (key, observer) => {
    if(!observers.has(key)){
      observers.set(key, []);
    }
    observers.get(key).push(observer);
  }

  const removeObserver = (key, observer) => {
    if(observers.has(key)){
      const filtered = observers.get(key).filter((obs) => obs !== observer);
      observers.set(key, filtered);
    }
  }

  const notify = (key, data) => {
    if(observers.has(key)){
      observers.get(key).forEach((observer) => observer(data))
    }
  }

  const subscribe = (key, callback) => {
    addObserver(key, callback)
    return () => removeObserver(key, callback)
  }

  return {notify, subscribe}
}

export const subject = createSubject();

 

 

`addObserver`는 `observers`에다 특정 key값을 두고 특정 callback을 등록(push) 시킵니다.

const observers = new Map();

const addObserver = (key, observer) => {
  if(!observers.has(key)){
    observers.set(key, []);
  }
  observers.get(key).push(observer);
}

 

`notify`는 특정 key값에 맞는 callback을 전부 실행시킵니다.

const notify = (key, data) => {
  if(observers.has(key)){
    observers.get(key).forEach((observer) => observer(data))
  }
}

 

`subscribe`는 옵저버를 구독하는 역할을 합니다.

const subscribe = (key, callback) => {
  addObserver(key, callback)
  return () => removeObserver(key, callback)
}

 

useCounterObserver.js

import React, { useEffect, useState } from 'react'
import { subject } from './Subject';

export const useCounterObserver = () => {
  const [state, setState] = useState(0);

  useEffect(() => {
    const unsubscribe = subject.subscribe('counter', setState);
  
    return () => unsubscribe();
  }, [])
  
  // 상태를 업데이트하고 구독자들에게 알림을 주는 함수
  const increment = () => {
    const newState = state + 1;
    subject.notify('counter', newState) // 'counter'업데이트 
  }

  return [state, increment]
}

export default useCounterObserver

 

화면이 렌더링 됐을 때 `counter`라는 key값으로 옵저버를 등록하고 `callback`으로 setState를 넘겨주고 있습니다.

const [state, setState] = useState(0);

useEffect(() => {
  const unsubscribe = subject.subscribe('counter', setState);

  return () => unsubscribe();
}, [])

 

`increment`는 상태를 업데이트하고 구독자들에게 알림을 주는 함수입니다.

const increment = () => {
  const newState = state + 1;
  subject.notify('counter', newState) // 'counter'업데이트 
}

 

App.jsx

import './App.css'
import useCounterObserver from './useCounterObserver'

const CounterComponent = () => {
  const [count, increment] = useCounterObserver();
  return (
    <div>
      <p>count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  )
}

function App() {
  return (
    <div>
      <h1>옵저버 패턴</h1>
      <CounterComponent />
      <CounterComponent />
    </div>
  )
}

export default App

 

App.jsx에서 위 코드와 같이 버튼을 눌렀을 때 `counter`라는 key값을 공유하기 때문에 `count`값이 동일하게 증가합니다.

 

 

반응형

'공부 > TIL' 카테고리의 다른 글

[TIL] 24.07.18 Swiper 슬라이드  (0) 2024.07.18
[TIL] 24.07.17 쓰로틀링(성능 측정)  (0) 2024.07.17
[TIL] 24.07.16 코딩 컨벤션이란?  (0) 2024.07.16
[TIL] 24.07.15  (0) 2024.07.15
[TIL] 24.07.09 백준 10844번 js  (0) 2024.07.09
[TIL] 24.07.08  (0) 2024.07.08
[TIL] 24.06.17 백준 1373번 js  (0) 2024.06.17
[TIL] 24.06.12 백준 1676번 js  (2) 2024.06.12