# 옵저버 패턴, PubSub 패턴

---

### 옵저버 패턴

옵저버 패턴은 1:N 관계가 있을 때, 한 객체의 상태가 변경되면 모든 종속 객체가 자동으로 알림을 받고 업데이트 되도록 하는 패턴이다. 이 패턴은 단일 객체에 대한 변경 사항을 알려야 하는 여러 객체가 있을 때 유용하다.

단 발행자와 수신자가 긴밀하게 커플링되어 있다. 때문에 로직 변경에 신경써야 한다.

```
class Subject {
  constructor() {
    this.observers = [];
  }

  subscribe(observer) {
    this.observers.push(observer);
  }

  unsubscribe(observer) {
    this.observers = this.observers.filter(o => o !== observer);
  }

  notify() {
    this.observers.forEach(observer => observer.update());
  }
}

class Observer {
  constructor(name) {
    this.name = name;
  }

  update() {
    console.log(`${this.name} 이 메시지를 받았습니다.`);
  }
}

const subject = new Subject();
const observer1 = new Observer('bob');
const observer2 = new Observer('alex');
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify();
subject.unsubscribe(observer1);
subject.notify();
```

### Pub-Sub 패턴

Pub-Sub 패턴은, 옵저버 패턴과 개념은 유사하지만, N:N 관계에 사용할 수 있다. 중간에 메시지 브로커가 있고, 특정 토픽을 변경하면 그 토픽을 구독하고 있는 모든 구독자에게 메시지를 보내는 형태이다. 따라서 발행자와 구독자는 서로가 누구인지 알 필요가 없고, 이 때문에 서로 디커플링을 유지하기 쉽다.

다음 예제를 보자.

```
class MessageBroker {
  constructor() {
    this.subscriptions = new Map();
  }

  subscribe(topic, subscriber) {
    let subscribers = this.subscriptions.get(topic);
    if (!subscribers) {
      subscribers = new Set();
      this.subscriptions.set(topic, subscribers);
    }
    subscribers.add(subscriber);
  }

  unsubscribe(topic, subscriber) {
    const subscribers = this.subscriptions.get(topic);
    if (subscribers) {
      subscribers.delete(subscriber);
      if (subscribers.size === 0) {
        this.subscriptions.delete(topic);
      }
    }
  }

  publish(topic, message) {
    const subscribers = this.subscriptions.get(topic);
    if (subscribers) {
      subscribers.forEach(subscriber => {
        subscriber.receive(topic, message);
      });
    }
  }
}

class Subscriber {
  receive(topic, message) {
    throw new Error('receive 로직 구현이 필요합니다.')
  }
}

class User extends Subscriber {
  constructor(name) {
    this.name = name;
  }

  receive(topic, message) {
    console.log(`${this.name} 님이 메시지를 받았습니다. ${topic}: ${message}`);
  }
}

const messageBroker = new MessageBroker();
const gameSubscriber = new User('bob');
const techSubscriber = new User('alex');

messageBroker.subscribe('game', gameSubscriber);
messageBroker.subscribe('tech', techSubscriber);

messageBroker.publish('game', '피파온라인5 출시');
messageBroker.publish('tech', 'gpt5 출시');

```

For the site tree, see the [root Markdown](https://slashpage.com/develop.md).
