CS/디자인 패턴

옵저버 패턴 (Observer Pattern)

Dahoon06 2023. 9. 11. 11:43
728x90
반응형

주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 알려주는 디자인 패턴

 

주체란? 객체의 상태 변화를 보고 있는 관찰
옵저버들이란? 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 "추가 변화 사항"이 생기는 객체들을 의미

 

 

옵저버 패턴은 다른 디자인 패턴과 다르게 일대다 (one-to-many) 의존성을 가진다.

 

옵저버 패턴의 특징

 

  • 애플리케이션이 한정된 시간, 특정한 케이스에만 다른 객체를 관찰해야하는 경우
  • 대상 객체의 상태가 변경될 때마다 다른 객체의 동작을 트리거해야할 때
  • 한 객체의 상태가 변경되면 다른 객체도 변경해야할 때
  • MVC 패턴
    • Model 과 View 의 관계는 옵저버 패턴의 Subject 역할과 Observer 역할의 관계와 대응됨
    • 하나의 Model에 여러 개의 View 가 사용된다.

 

 

장점

 

  • Subject의 상태 변경을 주기적으로 조회하지 않고 자동으로 감지할 수 있다.
  • 발행자의 코드를 변경하지 않고도 새 구독 클래스를 도입할 수 있어 개방-폐쇄 원칙(OCP)에 준수
  • 런타임 시점에서 발행자와 구독 알림 관계를 맺을 수 있다.
  • 상태를 변경하는 객체 (Subject) 와 변경을 감지하는 객체 (Observer)의 관계를 느슨하게 유지할 수 있다.

 

단점

 

  • 구독자는 알림 순서에 제어할 수 없고, 무작위로 알림을 받는다.
  • 옵저버 패턴을 자주 구성하면 구조와 동작을 알아보기 힘들어져 코드 복잡도가 증가한다.
  • 다수의 옵저버 객체를 등록 이후 해지하지 않는다면 메모리 누수가 발생할 수 있다.

 

 

자바스크립트를 활용한 옵저버 패턴

 

자바스크립트에서 옵저버 패턴을 활용하기 위해서는 프록시 객체를 통해 구현할 수 있다.

 

💡 프록시 객체

특정 객체를 감싸 프로퍼티 읽기, 쓰기와 같은 객체에 가해지는 작업을 중간에서 가로채는 객체

target: 프록시할 대상
handler: 프록시 객체의 target 동작을 가로채서 정의할 동작들이 정해져 있는 함수

 

const handler = {
	get: function (target, name) {
    	return name === 'name' ? `${target.a} ${target.b}` : target[name];
    }
}

const p = new Proxy({a: 'KUNDOL', b: 'IS AUMUMU ZANGIN'}, handler);
console.log(p.name) // KUNDOL IS AUMUMU ZANGIN

 

코드를 살펴보면 p 에는 name 이라는 속성이 없다.

하지만 Proxy 객체를 통하여 name 이라는 속성으로 접근했을 때 target에 들어온 값으로 문자열을 만들어 return 하도록 되어있고, name으로 접근했을 때 Proxy 객체가 이를 가로채 문자열을 만들어 반환하는 것을 알 수 있다.

 

function createReactiveObject(target, callback) {
	const proxy = new Proxy(target, {
    	set(obj, prop, value) {
        	if (value !== obj[prop]) {
            	const prev = obj[prop];
                obj[prop] = value;
                callback(`${prop} 이 [${prev}] -> [${value}] 로 변경되었습니다.`);
            }
            return true;
        }
    });
    return proxy;
}

/*=============================================================================*/

const a = { name: '다훈' };
const b = createReactiveObject(a, console.log);

b.name = '전다훈'; // name 이 [다훈] -> [전다훈] 로 변경되었습니다.
b.name = '훈다';   // name 이 [전다훈] -> [훈다] 로 변경되었습니다.

 

 

 

728x90
반응형

'CS > 디자인 패턴' 카테고리의 다른 글

선언형과 함수형 프로그래밍  (0) 2023.09.11
MVVM 패턴  (0) 2023.09.11
전략 패턴 (Strategy Pattern)  (0) 2023.09.11
팩토리 패턴 (Factory Pattern)  (0) 2023.09.11
싱글톤 (Singleton Pattern)  (0) 2023.09.11