观察者模式Observer Pattern

UML类图

观察者模式Observer Pattern

Observer(观察者基类)

  • 为那些在目标发生改变时需获得通知的对象定义一个更新接口

Subject(观察目标基类,可以理解为通知者)

  • 目标知道它的观察者(它被那些观察者观察)。可以有任意多个观察者观察同一个目标;

  • 提供注册和注销观察者对象的接口。

ConcreteObserver(具体的观察者)

  • 维护一个指向ConcreteSubject对象的引用;

  • 存储有关状态,这些状态应与目标的状态保持一致;

  • 实现Observer的更新接口以使自身状态与目标的状态保持一致。

ConcreteSubject(具体的被观察者即观察目标)

  • 将有关状态存入各ConcreteObserver对象;

  • 当它的状态发生改变时,向它的各个观察者发出通知

一、定义:观察者模式又被称为:发布订阅模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。可以理解为一个对象行为的改变,其相关联的对象都会得到通知,并自动产生对应的行为。

二、适用场景:在以下任一情况下都可以使用观察者模式:

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;

  • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;

  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。

  • 凡是涉及到消息更新、广播机制、消息传递、链式触发都可以考虑使用观察者模式

三、“观察”不是“直接调用”

实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。不管是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

四、实现形式:

实现观察者模式有非常多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式。

观察者模式按照以下方式进行协作:

  • 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者;

  • 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致

五、应用实例:

  • 拍卖的时候,拍卖师观察最高标价,然后通知给其他竞价者竞价。

  • 西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水招来一个老乌龟,这个乌龟就是观察者,他观察菩萨洒水这个动作。

  • 对同一组数据进行统计分析时候, 我们希望能够提供多种形式的表示 (例如以表格进行统计显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据, 我们当然需要当数据改变的时候, 所有的统计的显示都能够同时改变。

六、实例代码

点击查看代码
/*
*一般情况下,观察目标只有一个,即一对多的关系
*/
// observer.h
#include <list>

//通知的消息类型
enum class NotifyType
{
    Eat = 0,
    Drink,
    Play,
    Work,
};

class Observer;

//通知者(观察目标)
class Subject
{
protected:
    std::list<Observer*> m_observers;
public:
    void attach(Observer*);   //注册(添加一个观察者)
    void detach(Observer*);   //注销(删除一个观察者)
    virtual void notify() = 0; //通知
};

//观察者
class Observer
{
public:
    virtual void update(NotifyType type) = 0;  //更新
    virtual ~Observer() {};
};

//具体的观察者:员工A
class WorkerA :public Observer
{
    void update(NotifyType type) override;
};

//具体的观察者:员工B
class WorkerB :public Observer
{
    void update(NotifyType type) override;
};

//具体的观察者:员工C
class WorkerC :public Observer
{
    void update(NotifyType type) override;
};

//具体的通知者:组长
class Leader :public Subject
{
public:
    void notify() override;
};

//具体的通知者:经理
class Manager :public Subject
{
public:
    void notify() override;
};

//具体的通知者:老板
class Boss :public Subject
{
public:
    void notify() override;
};

// observer.cpp
#include "observer.h"
#include <iostream>

void Subject::attach(Observer* obs)
{
    m_observers.emplace_back(obs);
}

void Subject::detach(Observer* obs)
{
    auto it = m_observers.begin();
    while (it != m_observers.end())
    {
        if (*it == obs)
            m_observers.erase(it);
        it++;
    }
}

void Leader::notify()
{
    //组长通知一起去洗脚
    std::cout << "t组长发通知了n";
    for (const auto& elem : m_observers)
    {
        elem->update(NotifyType::Play);
    } 
}

void Manager::notify()
{
    //经理通知今晚加班
    std::cout << "t经理发通知了n";
    for (const auto& elem : m_observers)
    {
        elem->update(NotifyType::Work);
    }
}

void Boss::notify()
{
    //老板通知今晚一起吃饭喝酒
    std::cout << "t老板发通知了n";
    for (const auto& elem : m_observers)
    {
        elem->update(NotifyType::Eat);
        elem->update(NotifyType::Drink);
    }
}

void WorkerA::update(NotifyType type)
{
    switch (type)
    {
    case NotifyType::Eat:
        std::cout << "WorkerA:t去吃饭咯。n";
        break;
    case NotifyType::Drink:
        std::cout << "WorkerA:t去喝酒咯。n";
        break;
    case NotifyType::Play:
        std::cout << "WorkerA:t去洗脚咯。n";
        break;
    case NotifyType::Work:
        std::cout << "WorkerA:t装作认真工作的样子。n";
        break;
    default:
        break;
    }
}

void WorkerB::update(NotifyType type)
{
    switch (type)
    {
    case NotifyType::Eat:
        std::cout << "WorkerB:t我不去吃饭。n";
        break;
    case NotifyType::Drink:
        std::cout << "WorkerB:t我不去喝酒。n";
        break;
    case NotifyType::Play:
        std::cout << "WorkerB:t一起去洗脚咯。n";
        break;
    case NotifyType::Work:
        std::cout << "WorkerB:t加你麻痹班!n";
        break;
    default:
        break;
    }
}

void WorkerC::update(NotifyType type)
{
    switch (type)
    {
    case NotifyType::Eat:
        std::cout << "WorkerC:t我先回家了。n";
        break;
    case NotifyType::Drink:
        std::cout << "WorkerC:t我不会喝酒。n";
        break;
    case NotifyType::Play:
        std::cout << "WorkerC:t这次去哪洗脚?n";
        break;
    case NotifyType::Work:
        std::cout << "WorkerC:t我要带孩子先溜了,你们好好加班。n";
        break;
    default:
        break;
    }
}
// main.cpp
#include "observer.h"

int main()
{   
    //观察目标对象
    Subject* leader = new Leader();
    Subject* manager = new Manager();
    Subject* boss = new Boss();

    //观察者对象
    Observer* workerA = new WorkerA();
    Observer* workerB = new WorkerB();
    Observer* workerC = new WorkerC();

    //给观察目标添加观察者
    leader->attach(workerA);
    leader->attach(workerB);
    leader->attach(workerC);

    manager->attach(workerA);
    manager->attach(workerB);
    manager->attach(workerC);

    boss->attach(workerA);
    boss->attach(workerB);
    boss->attach(workerC);

    //观察目标状态改变发出通知
    leader->notify();
    manager->notify();
    boss->notify();

    return 0;
}

参考:
设计模式之观察者模式(c++)

观察者模式的程序实例C++

原文链接: https://www.cnblogs.com/mmmmmmmmm/p/14838575.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    观察者模式Observer Pattern

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/404131

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月24日 下午6:42
下一篇 2023年4月24日 下午6:42

相关推荐