Observer Patternのコードの読み方

# はじめに

大規模なソフトウェアを読んでいて、Observer Patternのコードを読むといつも迷子になってしまう。

何かしらのイベントが発生すると、Subjectに事前に登録されているインスタンスのメソッドを呼び出す(本記事ではupdateメソッド)が、いつ、どこで、どんなインスタンスがSubjectに登録されたかは、Subjectのクラスだけを見てもわからない。

Observer Patternの全体の流れを理解して、
Subjectを生成している初期化処理が別の場所にあるので、そこを見なければいけない(本記事ではmain関数)。

# Observer Pattern

知らせる側（Subject）が通知先（Observer,Listener）を事前に登録しておいて、
Subjectに更新があれば、Observerのメソッドを呼び出すことで、変更を通知する仕組み。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15085/3042f7c6-8c46-95ce-a3b2-0cddfffa4da5.png)


[コードを実行する](https://godbolt.org/z/K8rThd98c)



## Subject/Observerを生成

Subject/Observerを生成して、SubjectにObserverを登録させる。
Subjectの変化に応じて、Observerのメソッドが暗黙的に呼び出されるようになる。

```c++
int main() {
    auto sub = make_shared<Subject>(10);
    auto obs = make_unique<Observer>();

    sub->subscribe(obs.get());

    cout << "current state:" << sub->getState() << endl;
    sub->setState(15);
    cout << "current state:" << sub->getState() << endl;
    sub->setState(20);
    cout << "current state:" << sub->getState() << endl;
    sub->setState(25);
    cout << "current state:" << sub->getState() << endl;
}
```

実行時の出力

```terminal
current state:10
Observer was notified update:15
current state:15
Observer was notified update:20
current state:20
Observer was notified update:25
current state:25
```

## Subjectの定義

Subject::subscribe(Object)がmainから呼び出さ、内部でObserverを保持する。
Subjectの内部状態が変化する毎に、保持したObserverのupdae()を呼び出す。

```c++
class Subject {
 public:
    Subject(int s) : m_state{s}, m_observers{} {}
    virtual ~Subject() = default;
    
    // Subject::subscribe()がmain()から呼ばれる
    void subscribe(Observer* x) {
        x->setObject(this);
        m_observers.push_back(x);
    }
    int getState() const {
        return m_state;
    }
    void setState(int s) {
        m_state=s;
        notify();
    }

 private:
    void notify() {
        for(auto& i: m_observers){
            i->update();
        }
    }

    int m_state;
    vector<Observer*> m_observers;
};

```

## Observerの定義

ObserverがSubjectを持てるようにsetObject()を用意する。
Subjectの変化時にupdate()が呼び出される。

```c++
class Observer {
 public:
    Observer() = default;
    virtual ~Observer() = default;

    void setObject(Subject* s) {
        m_subject.reset(s);
    }
    void update();

 private:
    unique_ptr<Subject> m_subject;
}

// CallBack
void Observer::update(){
    cout << "Observer was notified update:" << m_subject->getState() << endl;
}

```


# コード全文

[コードを実行する](https://godbolt.org/z/K8rThd98c)

```c++
#include<iostream>
#include<vector>
#include<memory>
using namespace std;

class Subject;

class Observer {
 public:
    Observer() = default;
    virtual ~Observer() = default;

    void setObject(Subject* s){
        m_subject.reset(s);
    }
    void update();

 private:
    unique_ptr<Subject> m_subject;
};

class Subject{
 public:
    Subject(int s) : m_state{s}, m_observers{} {}
    virtual ~Subject() = default;
    
    // Subject::subscribe()がmain()から呼ばれる
    void subscribe(Observer* x){
        x->setObject(this);
        m_observers.push_back(x);
    }
    int getState(){
        return m_state;
    }
    void setState(int s){
        m_state=s;
        notify();
    }

 private:
    void notify(){
        for(auto& i: m_observers){
            i->update();
        }
    }

    int m_state;
    vector<Observer*> m_observers;
};

void Observer::update(){
    cout << "Observer was notified update:" << m_subject->getState() << endl;
}


int main() {
    auto sub = make_shared<Subject>(10);
    auto obs = make_unique<Observer>();

    sub->subscribe(obs.get());

    cout << "current state:" << sub->getState() << endl;
    sub->setState(15);
    cout << "current state:" << sub->getState() << endl;
    sub->setState(20);
    cout << "current state:" << sub->getState() << endl;
    sub->setState(25);
    cout << "current state:" << sub->getState() << endl;
}
```

# 参考サイト

[ゲームプログラマのためのデザインパターン（オブザーバ）](https://qiita.com/narumi_/items/699a51b3df0e8a418f60)