옵저버 패턴 (Observer Pattern)

옵저버 패턴은 주체(Subject)가 특정 객체의 상태를 관찰하다가 변화가 감지되면, 해당 객체를 구독(Subscribe)하고 있는 옵저버(Observer)들에게 변화를 통지하는 디자인 패턴이다.

이 패턴의 핵심은 주체와 옵저버를 분리하여 느슨한 결합을 유지하는 것에 있다. 이는 이벤트 기반 시스템이나 MVC(Model-View-Controller) 패턴에서 데이터 변경에 따른 화면 업데이트를 구현할 때 주로 사용된다.

이해를 돕기 위해 특정 유튜브 채널과 구독자, 혹은 SNS 계정과 팔로워의 관계를 생각하면 쉽다. 채널에 새 영상이 올라오면(상태 변화), 서버(주체)는 구독 중인 유저들(옵저버)에게 알림을 보낸다.

주체 : 객체의 상태 변화를 감시하고 알림을 보내는 관찰자 역할
옵저버 : 상태 변화에 따라 전달되는 메서드 등을 기반으로 동작하는 객체들을 의미

기본 구현 예시

자바스크립트에서 배열과 함수를 활용해 기본적인 옵저버 패턴을 구현하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
let isUpdate = false;
const subscriber = []

const update = () => {
	isUpdate = true;
	notify();
}

const notify = () => {
		if(isUpdate) {
			msg = "check it!"
		  console.log("new post")
	    subscriber.forEach((user) => user(msg))
	    isUpdate = false
		}
}

const subcribe  = (user) => subscriber.push(user)
subcribe((msg) => console.log(`user1 ${msg}`))
subcribe((msg) => console.log(`user2 ${msg}`))

update();

subscribers 리스트에 알림을 받을 대상(함수)을 담아두고, update()가 실행되는 순간 등록된 모든 함수가 자동으로 호출되는 구조를 가진다.

Proxy 객체를 활용한 구현

옵저버 패턴은 자바스크립트의 Proxy 객체를 통해서도 효율적으로 구현이 가능하다. Proxy는 실제 데이터 객체 앞단에서 동작하며, 누군가가 데이터를 읽거나 쓸 때 그 작업을 가로채 사용자가 정의한 작업을 수행하도록 돕는다.

Proxy 객체는 대상 객체인 target과 가로챌 동작을 정의한 handler를 매개변수로 가진다. 주로 get(), set(), has() 등의 핸들러를 사용하여 속성 접근을 제어한다. 이 외에의 핸들러는 MDN 홈페이지에서 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const handler = {
    set : (obj,props,value) => {
    if(value != obj[props]){
        const prev = obj[props]
        obj[props] = value
        console.log(`${props}가 [${prev}] >> [${value}]로 변경`)
    }
    return true
} }

const post = {
    'likes' : 0
}
const feed = new Proxy(post, handler)
feed.likes = 100

Proxy의 set() 함수는 속성 값의 변경을 감지한다. 위 예제에서는 likes 속성이 0에서 100으로 변경되는 과정을 가로챈다.

마치며

옵저버 패턴은 상태 변화에 따른 자동화를 구현할 때 유용하다. 특히 자바스크립트의 Proxy를 활용하면 데이터 객체의 변화를 직접적으로 감시할 수 있어 코드의 직관성을 높일 수 있다.

카테고리:

업데이트: