Observer pattern을 간단히 말하자면, subject라는 object가 observer라는 object의 목록을 유지 관리하면서 observer들의 상태 변경을 자동으로 알려주는 design pattern이라고 할 수 있습니다. Subject가 observer들에게 특정 알림을 보내고 싶을 때는 해당 정보를 observer들에게 broadcast 합니다. 특정 observer에게 더이상 알림을 보내고싶지 않을때는 observer 목록에서 해당 observer들을 삭제하면 됩니다.
GoF의 Design Patterns: Elements of Reusable Object-Oriented Software 에서는 Observer pattern을 다음과 같이 정의하고 있습니다.
“One or more observers are interested in the state of a subject and register their interest with the subject by attaching themselves. When something changes in our subject that the observer may be interested in, a notify message is sent which calls the update method in each observer. When the observer is no longer interested in the subject’s state, they can simply detach themselves.” 하나 이상의 observer가 subject의 상태에 관심을 갖고 있으며, 해당 subject에 자신들(observer)을 등록합니다. Observer가 관심을 가지고 있는 subject의 상태가 변경되면, 각 observer의 update method에 알림 메시지가 전송됩니다. Observer가 더 이상 subject의 상태에 관심이 없다면, 간단히 observer와 subject간의 등록을 끊을 수 있습니다.
이제, Observer pattern을 구현하기 위해 필요한 요소들을 살펴보겠습니다.
- Subject : Observer의 목록을 유지보수. Observer의 추가 제거.
- Observer : Observer의 상태가 변경되었을 때의 알림을 받는 update interface 를 제공.
- ConcreteSubject : 상태 변화에 따른 알림을 observer에게 broadcast 하고, ConcreteObservers의 상태를 저장.
- ConcreteObserver : ConcreteSubject에 대한 reference를 저장하며, Subject의 상태와 일치하도록 Observer에 대한 update interface 를 구현.
class ObserverList {
constructor() {
this.observerList = [];
}
add(obj) {
return this.observerList.push(obj);
}
count() {
return this.observerList.length;
}
get(index) {
if (index > -1 && index < this.observerList.length) {
return this.observerList[index];
}
}
indexOf(obj, startIndex) {
let i = startIndex;
while (i < this.observerList.length) {
if (this.observerList[i] === obj) {
return i;
}
i++;
}
return -1;
}
removeAt() {
this.observerList.splice(index, 1);
}
}
class Subject {
constructor() {
this.observers = new ObserverList();
}
addObserver(observer) {
this.observers.add(observer);
}
removeObserver(observer) {
this.observers.removeAt(this.observers.indexOf(observer, 0));
}
notify(context) {
let observerCount = this.observers.count();
let i;
for (i = 0; i < observerCount; i++) {
this.observers.get(i).update(context);
}
}
}
위의 코드는 subject와, subject에서 사용하는 observer list를 class로 구현한 것입니다. 위의 코드에서 사용하는 observer object는 아래와 같이 update method가 꼭 구현되어야 합니다.
class Observer {
update(context) {
// blah blah..
}
}