Observer pattern - meruneru/tech_memo GitHub Wiki

Observer pattern

本稿はQiitaにも載せた。

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

コード実行

#include<iostream>
#include<vector>
#include<memory>
using namespace std;

class Subject;

class Observer{
public:
    Observer(void){}
    virtual ~Observer(void){}

    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;}
    virtual ~Subject(void){};
    
    // Subject::subscribe()がmain()から呼ばれる
    void subscribe(Observer* x){
        x->setObject(this);
        m_observers.push_back(x);
    }
    int getState(void){
        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(){
    shared_ptr<Subject> sub(new Subject(10));
    unique_ptr<Observer> obs(new 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;
    return 0;    
}

Subject/Observerを生成

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

int main(){
    shared_ptr<Subject> sub(new Subject(10));
    unique_ptr<Observer> obs(new 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;
    return 0;    
}

実行時の出力

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()を呼び出す。

class Subject{
public:
    Subject(int s){m_state=s;}
    virtual ~Subject(void){};
    
    // Subject::subscribe()がmain()から呼ばれる
    void subscribe(Observer* x){
        x->setObject(this);
        m_observers.push_back(x);
    }
    int getState(void){
        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()が呼び出される。

class Observer{
public:
    Observer(void){}
    virtual ~Observer(void){}

    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;
}

参考サイト

ゲームプログラマのためのデザインパターン(オブザーバ)

⚠️ **GitHub.com Fallback** ⚠️