옵저번 패턴은 객체 간의 일대다 의존 관계를 정의하는 패턴
어떤 객체의 상태가 변할 때, 그 객체에 의존하는 다른 객체들이 이 변화를 통지받아 자동으로 업데이트될 수 있도록 하는 구조
객체 간의 결합도를 낮추고, 확장성을 높이는데 도움을 줌
비동기적인 이벤트 처리에 유용하며, 객체 간의 강한 결합을 피하고, 이벤트가 발생할 때마다 관련된 옵저버들이 동작할 수 있도록 해줌
새로운 옵저버를 추가하거나 기존의 옵저버를 제거하는 것이 간단해 코드의 유지보수성과 확장성을 높이는데 도움
주체와 옵저버가 각각 독립된 객체로 존재하기 때문에 코드의 재사용성과 모듈화가 강화됨
이벤트 기반의 자바스크립트에 적합
옵저버가 등록된 순서대로 이벤트를 받기 때문에, 순서가 중요하지 않은 경우 번거로울 수 있음
주체에서 옵저버를 명시적으로 제거하지 않을 경우 메모리 누수가 일어날 수 있음
이벤트가 발생할 때마다 모든 옵저버에게 통지되므로, 성능에 영향을 줄 수 있음
규모가 커지면서 관리해야할 옵저버의 수가 많아질 경우 코드가 복잡해질 수 있음
상태를 관리하는 주체 객체
옵저버들을 등록하고, 상태가 변할 때 등록된 옵저버들에게 알림을 보냄
주체의 상태 변화를 감시하고, 변화가 있을 경우 특정 동작을 수행하는 객체
주체에 등록되어 있어야 하며, 주체로부터 상태 변화에 대한 통지를 받게 됨
class Observable {
constructor() {
this.observers = []; // 이벤트가 일어날때 알릴 observers list
}
subscribe(func) { // observers list에 observer를 추가하는 메서드
this.observers.push(func);
}
unsubscribe(func) { // observers list에서 observer를 제거하는 메서드
this.observers = this.observers.filter((observer) => observer !== func);
}
notify(data) { // 이벤트가 일어날 때 모든 observers에게 알리는 메서드
this.observers.forEach((observer) => observer(data));
}
}
export default function App() {
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
</div>
);
}
import { ToastContainer, toast } from "react-toastify";
function logger(data) {
console.log(`${Date.now()} ${data}`);
}
function toastify(data) {
toast(data);
}
export default function App() {
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
<ToastContainer />
</div>
);
}
import { ToastContainer, toast } from "react-toastify";
function logger(data) {
console.log(`${Date.now()} ${data}`);
}
function toastify(data) {
toast(data);
}
observable.subscribe(logger);
observable.subscribe(toastify);
export default function App() {
function handleClick() {
observable.notify("User clicked button!");
}
function handleToggle() {
observable.notify("User toggled switch!");
}
return (
<div className="App">
<Button>Click me!</Button>
<FormControlLabel control={<Switch />} />
<ToastContainer />
</div>
);
}