設計模式之觀察者模式(ObserverPattern)

設計模式之觀察者模式(ObserverPattern)


一.觀察者模式(ObserverPattern)

在生活中會遇到很多使用觀察者模式的案例,比如股票跌漲後,股民作爲觀察者會對股票進行交易;客人來敲門,門鈴響了之後管家就會去開門等等。其中觀察者與被觀察者都有相互聯繫。

注: 接下來爲了方便理解類之間的設計關係,採用StartUML畫類圖,用C++編程

二.編程實例

1.進制轉換器

其中需要注意的有兩個點:
1.Subject類與Observer類之間相互關聯。
2.因爲只要Subject模型一改變,所有的Observer派生類都要改變,所以Observer抽象類用static修飾Subject變量
3.一旦創建了新的Observer派生類,首先賦值Subject(被觀察的類),然後將自己添加到Subject的通知對象中
類圖設計
在這裏插入圖片描述
程序

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

/*
設計模式:觀察者模式(Observer Pattern)

*/

/********************************觀察者Observer***************************/
class Subject;
class Observer
{
public:
    static Subject* _subject;//因爲只要Subject一改變,所有的Observer派生類都要改變,所以用static修飾
public:
    virtual ~Observer(){}
    virtual void update() = 0;
};
Subject* Observer::_subject;


/********************************定義被觀察的對象Subject***************************/
class Subject
{
    vector<Observer*> _observers;
    size_t _number;
public:


    size_t getNumber()const
    {
        return _number;
    }
    void setNumber(size_t number)
    {
        _number = number;
        notifyAllObservers();
    }
    void attachObserver(Observer* observer)
    {
        _observers.push_back(observer);
    }
    void notifyAllObservers()
    {
        for (auto& e: _observers)
            e->update();
    }
};


/********************************Observer派生類***************************/
//8進制
class OctObserver:public Observer
{
public:
    OctObserver(Subject* subject)
    {
        _subject = subject;
        _subject->attachObserver(this);//一旦創建了新的Observer派生類,首先賦值Subject(被觀察的類),然後將自己添加到Subject的通知對象中
    }

    void update()
    {
        cout << "Oct:" << oct << _subject->getNumber() << endl;
    }
};


//10進制
class DecObserver:public Observer
{
public:
    DecObserver(Subject* subject)
    {
        _subject = subject;
        _subject->attachObserver(this);
    }

    void update()
    {
        cout << "Dec:" << dec << _subject->getNumber() << endl;
    }
};


//16進制
class HexObserver:public Observer
{
public:
    HexObserver(Subject* subject)
    {
        _subject = subject;
        _subject->attachObserver(this);
    }
    
    void update()
    {
        cout << "Hex:" << hex << _subject->getNumber() << endl;
    }
};




int main()
{
    unique_ptr<Subject> up(new Subject());
    new DecObserver(up.get());
    new HexObserver(up.get());
    new OctObserver(up.get());
    up->setNumber(10);
    cout << "-----------------------" << endl;

    up->setNumber(16);

    return 0;
}


2.客人敲門案例

假設有客人,門鈴,嬰兒,護工四個類。
門鈴是Subject被觀察者,嬰兒和護士是觀察者。
嬰兒和護工隨時觀察門鈴,客人按動鈴鐺的時候,嬰兒開始哭,護工去開門。
類圖設計
在這裏插入圖片描述
程序

#include <iostream>
#include <memory>
#include <list>
#include <cstdio>
#include <algorithm>
using namespace std;

/*
觀察者模式實際案例:
假設有客人,門鈴,嬰兒,護工四個類。
門鈴是Subject被觀察者,嬰兒和護士是觀察者。
嬰兒和護工隨時觀察門鈴,客人按動鈴鐺的時候,嬰兒開始哭,護工去開門。

下面是案例設計的UML類圖,完成程序:
*/

/***********************Observer AND Subject*****************************/
class Observer
{
public:
    virtual string name() const = 0;
    virtual void update() = 0;
};

class Subject
{
public:
    virtual void attach(Observer *) = 0;
    virtual void detach(Observer *) = 0;
    virtual void notify() = 0;
};

/***********************Baby AND Nurse*****************************/
class Baby : public Observer
{
    string _name;

public:
    Baby(string name)
        : _name(name)
    {
    }

    string name() const { return _name; }

    void update()
    {
        cout << _name << " is Crying" << endl;
    }
};

class Nurse : public Observer
{
    string _name;

public:
    Nurse(string name)
        : _name(name)
    {
    }

    string name() const { return _name; }

    void update()
    {
        cout << "Nurse is opening the door" << endl;
    }
};

/***********************Ring*****************************/
class Ring : public Subject
{
    list<Observer *> _oblist;
    // list<Observer *> _goldenlist;  //黃金會員
    // list<Observer *> _diamondlist; //鑽石會員

public:
    void attach(Observer *ob)
    {
        auto it = find(_oblist.begin(), _oblist.end(), ob);
        if (it == _oblist.end())
        {
            _oblist.push_back(ob);
        }
    }

    void detach(Observer *ob)
    {
        auto it = find(_oblist.begin(), _oblist.end(), ob);
        if (it != _oblist.end())
        {
            _oblist.erase(it);
        }
    }

    void alarm()
    {
        notify();
    }

    void notify()
    {
        for (auto &e : _oblist)
            e->update();
    }
};

/***********************Ring*****************************/
class Guest
{
    string _name;
public:
    Guest(string name)
        : _name(name)
    {
    }

    string name() const { return _name; }

    void knock(Ring* ring)
    {
        cout << _name << " is knocking the door" << endl;
        ring->alarm();
    }
};


int main()
{
    unique_ptr<Observer> baby1(new Baby("haha"));
    unique_ptr<Observer> baby2(new Baby("bala"));
    unique_ptr<Observer> nurse(new Nurse("gj"));

    unique_ptr<Ring> ring(new Ring());
    ring->attach(baby1.get());
    ring->attach(baby2.get());
    ring->attach(nurse.get());

    Guest guest("Uncle");
    guest.knock(ring.get());

    ring->detach(baby2.get());
    guest.knock(ring.get());

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章