본문 바로가기
프로그래밍/JAVASCRIPT

옵저버 패턴(Observer Pattern)이란?

by Lihano 2021. 8. 11.
반응형

디자인 패턴이라는 건 소프트웨어 개발을 하면서 발생하는 다양한 이슈들을 해결하는데 도움을 주는 기술들입니다. 많은 개발자들의 경험들을 바탕으로 만들어진 증명된 기술들이죠. 개발에 난항을 겪는 사람들에게는 참조할 수 있는 솔루션이 됩니다. 이게 프레임워크, 라이브러리 같은 도구들과 다른점은 순수한 패턴... 즉, 조언자의 역할만 한다는 거겠죠.

 

자바스크립트에는 대표적인 디자인 패턴들이 있습니다. 싱글톤 패턴, 팩토리 패턴, Iterotor 패턴, Decorator 패턴, 프록시 패턴, Mediator 패턴, Observer 패턴 등등이요. 각 패턴들이 어떤 용도로, 어떤 솔루션을 제공해주는지는 간략하게 요약해보겠습니다.

  • 싱글톤 패턴 : 특정 클래스의 객체를 한개만 유지하는 패턴
  • 팩토리 패턴 : 비슷한 객체를 공장에서 찍어내듯이 반복적으로 생성할 수 있게 하는 패턴
  • Iterator 패턴 : 객체의 내부 구조가 복잡하더라도 개별 속성에 쉽게 접근하기 위한 패턴
  • Decorator 패턴 : 런타임시 객체에 동적으로 부가기능을 추가할 수 있는 패턴
  • 프록시 패턴 : Lazy Initialization(게으른 초기화)로 어플리케이션의 부하를 줄여준다.
  • Mediator 패턴 : 객체 간의 영향도(결합도)가 높은 상태에서는 어플리케이션의 리팩토링이 예기치 않은 결과를 낼 수 있는데, 그때문에 결합도를 낮추기 위해 객체의 상태가 변경되면 Mediator에게 먼저 전달하고 이를 Mediator가 다른 객체에 전달하는 방식
  • Observer 패턴 : 클라이언트 측 자바스크립트 프로그래밍에서 널리 사용되는 패턴. 객체간의 결합도를 낮추기 위함.

 

제가 오늘 알아볼 건 옵저버 패턴에 관해서입니다. 객체간의 결합도를 낮추기 위해 사용한다고 제가 써놓았죠. 결합도라는 건 모듈간에 얼마나 상호의존성을 가지고 있느냐의 수준입니다. 그럼 이걸 왜 낮춰야할까요? 복잡성의 관리를 위해 분리한 모듈이 제대로 분리되지 않고 다른 모듈과 의도하지 않은 메서드나 프로퍼티를 공유한다면 안되겠죠? 그래서 의존성은 최소화하는 게 좋은겁니다.

 

옵저버 패턴의 작동 방식은 간단합니다. 모듈들에게 옵저버를 등록하여 상태 변화가 있을 때마다 메서드를 통해 옵저버에게 통지하도록 하는 시스템입니다. 모듈들은 상태 변화가 일어났을 대 관찰자(observer)에게 필요한 데이터와 함께 자신의 상태 변화를 통보합니다.

 

옵저버는 모듈한테 전달받은 데이터를 가지고 연관된 다른 모듈들이 이를 참조해 필요한 작업을 수행할 수 있도록 도와줍니다. 옵저버라는 녀석은 모듈들의 상태 변화를 통제하는 중간 관리자쯤 되는 녀석이겠네요. 

위키피디아의 그림을 참조하도록 합시다.

옆의 Subject가 옵저버를 등록한, 즉 관찰 대상이 되는 객체들입니다. 이 녀석들한테 특이할만한 이벤트가 발생하면 옵저버에게 콜백 함수라는 게 전달됩니다. 그림에선 notify() 함수가 되겠죠.

 

notify는 옵저버가 정의한 메소드입니다. 옵저버는 notify 함수를 통해 이벤트 발생시 어떤 동작을 처리할 것인가를 결정합니다.

// 서브젝트
class Subject {
  constructor() {
    this.observers = [];
  }
  // 옵저버 등록
  registerObserver(observer) {
    this.observers.push(observer);
  }
  // 옵저버 제거
  unregisterObserver(observer) {
    this.observers = this.observers.filter(
      (registedObserver) => registedObserver !== observer
    );
  }
  // 알려주는 함수
  notifyObservers(data) {
    // 함수로 넣었을 때
    // this.observers.forEach(observer => observer(data));
    this.observers.forEach((observer) => observer.notify(data));
  }
}

const subject$ = new Subject();

// 객체가 아닌 함수로 넣었을 때.
// const observer1 = data => console.log('first ' + data);
// const observer2 = data => console.log('second ' + data);
const observer1 = { notify: (str) => console.log("first " + str) };
const observer2 = { notify: (str) => console.log("second " + str) };

subject$.registerObserver(observer1);
subject$.registerObserver(observer2);

subject$.notifyObservers("noti");

위의 코드가 옵저버를 간단하게 구현한 코드입니다.

보면 알겠지만 서브젝트라는 녀석은 옵저버들을 가지는 배열과 옵저버를 등록하는 함수 그리고 제거하는 함수로 이루어져있습니다. 여기서 옵저버들은 함수를 넣었습니다. 옵저버가 하는 일은 서브젝트가 전달받은 데이터를 출력하는 일이죠.

 

굉장히 간단한 코드지만 옵저버 패턴의 정의를 알 수 있습니다.

서브젝트는 옵저버를 가지며, 옵저버에게 정보를 전달한다는 사실과

옵저버는 서브젝트에게 전달받은 데이터를 처리한다는 사실을요.

 

위의 간단한 예제가 아닌, 서브젝트에게 전달받은 코드를 다른 모듈들에게 전달하여 처리하게 할 수도 있습니다. 하지만 이 경우에는 굉장히 주의해야합니다. 만일 옵저버로부터 데이터를 전달받는 모듈도 옵저버를 가졌을 경우, 그 옵저버에 상태 변화가 전달되며 연쇄 작용이 일어날 수 있습니다.

 

 

참조

Javascript Pattern 요약 - 디자인 패턴 • 캡틴판교 (joshua1988.github.io)

디자인패턴 - 옵저버 패턴(Observer Pattern) (tistory.com)

옵서버 패턴 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

반응형

'프로그래밍 > JAVASCRIPT' 카테고리의 다른 글

클론 개발 후기..  (0) 2021.09.10
바벨(babel)이란 무엇인가?  (1) 2021.08.12
생성자(Constructor)란??  (0) 2021.08.11
번들링(Bundling)이란?  (0) 2021.08.11

댓글