nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

Observerパターンについて [C++]

Observerとは、英語で観察者を意味します。

Observer パターンとは、状態の変化を観察することを目的としたものですが、どちらかというと「観察」よりも「通知」に重点の置かれたものになっています。

あるインスタンスの状態が変化した際に、そのインスタンス自身が、「観察者」に状態の変化を「通知」する仕組みです。

<Observerパターンの定義 : クラス図>

f:id:nprogram:20170816230359p:plain

[ObserverSample.h]

#include <vector>
#include <algorithm>
#include <iostream>

class Observer {
    friend class Subject;
public:
    virtual ~Observer() {}
protected:
    virtual void update(Subject*) = 0;
};

class Subject {
private:
    std::vector<Observer*> obs_;

public:
    // Observerを登録
    void add_observer(Observer* o) {
        if (std::find(obs_.begin(), obs_.end(), o) == obs_.end()) {
            obs_.push_back(o);
        }
    }

    // Observerの登録抹消
    void delete_observer(Observer* o) {
        auto iter = std::find(obs_.begin(), obs_.end(), o);
        if (iter != obs_.end()) {
            obs_.erase(iter);
        }
    }
protected:
    // 登録されたObserverのハンドラを呼び出す
    // std::for_each ⇒ 範囲の全ての要素に、指定された関数を適用する
    // oの全ての要素にラムダ式を適用する
    // 【thisのキャプチャ】
    // メンバ関数内では、thisをキャプチャすることでラムダ式内でメンバ変数、メンバ関数(update)を使用することができます。
    // 下記のラムダ式では、thisをキャプチャして、vector[obs_]の各要素のObserverオブジェクトのupdateメソッドを使用しています。
    void notify() {
        std::for_each(obs_.begin(), obs_.end(),
            [this](Observer* o) { o->update(this); });
    }
};

// 具象サブジェクト
// 室温
class RoomTemp : public Subject {
private:
    int value_; //
public:
    RoomTemp(int initial) : value_(initial) {}
    void increment() // 室温を1度上げる
    {
        ++value_;
        notify();
    }
    void decrement() // 室温を1度下げる
    {
        --value_;
        notify();
    }
    int get_temp() const // 現在の室温
    {
        return value_;
    }
};

// 具象オブサーバクラス
// 温度表示パネル : 室温の変化に応じて室温を表示する
class TempDisp : public Observer {
public:
    ~TempDisp() { std::cout << "お疲れ様でしたー" << std::endl; }
protected:
    virtual void update(Subject* from) {
        int temp = static_cast<RoomTemp*>(from)->get_temp();
        std::cout << "現在の温度: " << temp << "℃" << std::endl;
    }
};

[main.cpp]

#include "ObserverSample.h"


int main() {
    RoomTemp room1(20);
    RoomTemp room2(30);
    TempDisp disp1;
    TempDisp disp2;
    room1.add_observer(&disp1);
    room2.add_observer(&disp2);
    room1.increment();
    room1.increment();
    room1.increment();
    room2.decrement();
    room2.decrement();
    room2.decrement();
}

実行結果

f:id:nprogram:20170816230627p:plain

以下のサイトを参考にさせていただきました。

codezine.jp

参考リンク

以下のリンクがわかりやすいです。 * 地下アイドルとアイドルオタクを疎結合にしてみたら、夢も希望もなくなった〜デザインパターンのObserverを考える〜 - Qiita