设计模式之观察者模式(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章