Development/디자인 패턴
Observer Pattern (Pub/Sub)
레오나르도 다빈츠
2025. 4. 10. 20:05
Observer Pattern 패턴
정의
옵저버 패턴 혹은 발행-구독(Pub/Sub) 패턴이라고도 불리는 이 디자인 패턴은 객체 간의 1:N 의존성을 정의해서, 어떤 객체의 상태가 변할 때 그에 의존하는 객체들에게 자동으로 알림이 가도록 설계된 패턴이다.
- Subject(Publisher): 상태를 가지고 있으며, 변경 사항이 생기면 옵저버(구독자)에게 알림.
- Observer(Subscriber): Subject를 구독하고 있으며, 상태 변화에 반응함.
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received: ${data}`);
}
}
const newsAgency = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");
newsAgency.subscribe(observer1);
newsAgency.subscribe(observer2);
newsAgency.notify("새 뉴스 도착!");
특징
- 느슨한 결합: Subject는 Observer에 대해 구체적인 정보를 몰라도 된다.
- 자동 업데이트: 상태가 바뀌면 구독자에게 자동으로 알림이 간다.
- 확장성: 옵저버를 동적으로 추가하거나 제거 가능하다.
React
리액트 어플리케이션의 기본적인 렌더링 자체가 옵저버 패턴이다.
1. Component 자체
React는 컴포넌트가 상태(state), props에 의존하고 이 값이 변경되면 자동으로 렌더링 된다.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
// count가 변경될 때마다 컴포넌트는 자동으로 "업데이트"된다
return (
<div>
<p>{count}번 클릭했어요</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
);
}
2. Context API + useContext
Context도 내부적으로 옵저버 패턴을 사용한다. 컴포넌트들이 특정 Context를 구독하고 있다가 값이 바뀌면 자동으로 업데이트 된다.
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext); // Context 값 구독
return <button className={theme}>버튼</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
3. Redux, Zustand, MobX
이 상태관리 라이브러리들이 옵저버 패턴 기반이다.
import { observer } from 'mobx-react-lite';
const Counter = observer(({ store }) => (
<button onClick={() => store.count++}>
{store.count}
</button>
));
const useStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
}));
function Counter() {
const count = useStore((state) => state.count); // 이 부분이 옵저버 역할
const increase = useStore((state) => state.increase);
return <button onClick={increase}>{count}</button>;
}