본문 바로가기
JavaScript/Core

[JavaScript] 옵저버 패턴(Observer Pattern)

by Jundol 2015. 1. 26.

옵저버패턴! or 감시자 패턴 or 커스텀이벤트 or 구독자패턴 이라고 불린다. ㅋㅋㅋ 


아주 유사패턴명이 수두룩하네.


흔히 이벤트로 보던 mouseover , keypress와 같은 브라우저 이벤트가 옵저버 패턴의 예들이다.


옵저버 패턴을 사용하는 이유는 객체간의 결합도를 느슨하게 하기위함이다. 객체들의 결합도가 높을수록 유지보수는 아주아주아주 힘든 작업이 된다. 

어떤 하나의 객체가 다른 객체의 메소드를 호출하는 대신, 객체의 특별한 행동을 감시하고 있다가 행동이 일어나면 알림을 받는다.



Sample

신문구독

 

  1. 신문사가 신문을 발행한다.
  2. 독자가 특정 신문사에 구독을 신청한다.
  3. 신문사가 영업하는 한 구독 및 해지가 발생한다.

 

월간신문과 일간신문이 있다고 정의한다. 신문사의 이름은 newyorkTimes라 한다.(뉴욕은 가본적이 없다.) 

독자 joe는 신문이 발행될때마다 '알림'을 받는다.

여기서 '알림'이란 독자(man) 객체의 메소드를 호출한다는 뜻이다. 따라서, 독자객체(man)는 구독할 때 자신의 메소드 중 하나를 newyorkTimes의 on()메소드에 전달해야 된다.

신문사는 독자가 원하면 구독을 해지해줄 수 있다. 해지하는 메소드는 remove 메소드라 한다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//신문사를 짓다.
var publisher = {
 subscribers: {
  any : [] // '이벤트 타입 : 구독자의 배열'의 형식
 },
 //등록
 on : function(fn, type) {
  type = type || 'any';
  if(typeof this.subscribers[type] === "undefined"){
   this.subscribers[type] = [];
  }
  this.subscribers[type].push(fn);
 },
 //구독해지
 remove : function(fn, type){
  this.visitSubscribers('remove', fn, type);
 },
 //알림
 fire : function(publication, type){
  this.visitSubscribers('fire', publication, type);
 },
 //신문사의 일하는 사람
 visitSubscribers : function(action, arg, type){
  var pubtype = type || 'any',
   subscribers = this.subscribers[pubtype],
   i,
   max = subscribers.length;
  for(i=0; i<max; i+=1){
   if(action==='fire'){
    subscribers[i](arg);
   }else{
    if(subscribers[i]===arg){
     subscribers.splice(i,1);
    }
   }
  }

 }
};

//객체를 받아 발행자 객체로 바꿔준다.
//단순히 해당 객체에 범용 발행자 메서드들을 복사해 넣는다.
function makePublisher(o){
 var i;
 for(i in publisher){
  if(publisher.hasOwnProperty(i) && typeof publisher[i] === "function"){
   o[i] = publisher[i];
  }
 }
 o.subscribers = { any: [] };
}

//newyorkTimes 신문사
var newyorkTimes = {
 daily : function() {
  this.fire("big news today");
 },
 monthly : function() {
  this.fire("monthly hot-issue", "monthly");
 }
};

//newyorkTimes를 발행자로 만든다.
makePublisher(newyorkTimes);

//구독자 객체 joe 생성
var joe = {
 drinkCoffe : function(daily){
  console.log(daily + '를 읽었습니다.');
 },
 sundayPreNap : function(monthly){
  console.log('월간 ' + monthly + ' 를 읽고있습니다.');
 }
};

//newyorkTimes의 구독자 목록에 joe를 추가한다.(joe가 paper를 구독한다.)
//나 이제 신문을 읽을 것이오~
//일간신문이 발행이 되면 내 drinkCoffe 메소드를 호출해주시오.
//월간신문이 발행이 되면 내 sundayPreNap 메소드를 호출해주시오.
newyorkTimes.on(joe.drinkCoffe);
newyorkTimes.on(joe.sundayPreNap, 'monthly');

//joe는 기본 이벤트 타입인 'any'이벤트 발생시 호출될 메서드와, 'monthly'타입의 이벤트 발생시 호출될 메서드를 전달했다.
//몇가지 이벤트를 발생
newyorkTimes.daily(); //"big news today를 읽었습니다."
newyorkTimes.daily(); //"big news today를 읽었습니다."
newyorkTimes.daily(); //"big news today를 읽었습니다."
newyorkTimes.monthly(); //"월간 monthly hot-issue 를 읽고있습니다."


 

참고 서적 : JavaScript Patterns [자바스크립트 코딩 기법과 핵심 기법] 저자 스토얀스테파노프 , 역자 : 김준기,변유진

참고 사이트 :

http://wiki.codekin.com/index.php/%EC%98%B5%EC%A0%80%EB%B2%84%ED%8C%A8%ED%84%B4(Observer_Pattern)

http://warmz.tistory.com/751

댓글