C++ 观察者模式

本文介绍了C++中的观察者模式,通过一个生动的商店购物比喻解释了观察者模式的概念,并与回调函数进行了对比。文章详细阐述了如何在C++中实现观察者模式,包括Observer观察者类、被观察对象的定义,以及在main函数中的应用。此外,还提供了相关参考资料链接供深入学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++ 观察者模式

Muduo不好啃,也怪自己之前没学过设计模式,如今只能临时抱佛脚了。

简介

什么是观察者模式?在学习这个设计模式之前,先要知道一件事情:回调函数(callback),在知乎上关于回调函数有一个形象的比喻:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。

作者:常溪玲
链接:https://www.zhihu.com/question/19801131/answer/13005983
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

经过一天的研究,我发现观察者模式跟回调函数很像,在一块理解起来很方便。

观察者模式又叫做发布-订阅模式,跟回调类似,接着上面的例子,你就是观察者,而店员就是对象,当到货之后(状态发生变化),就通知观察者。

关于具体概念,菜鸟还是不长篇大论了,还是偏理解为主,可以参考:http://blog.youkuaiyun.com/wuzhekai1985/article/details/6674984


实现

对muduo 源码中的~/recipes/thread/test/observer.cc做了一些修改。主要是进行简单的解耦操作。

Observer观察者

//Observer.h 
#ifndef __OBSERVER_H__
#define __OBSERVER_H__
#include <iostream>
#include <string>
#include "Observable.h"
class Observable;
class Observer//抽象类
{
    public:
        virtual ~Observer();
        virtual void update()=0;//纯虚函数

        void observe(Observable *s);//订阅
    protected:
        Observable* __subject;//订阅的对象
};
#endif
//Observer.cpp

#include "Observer.h"
#include "Observerable.h"

void Observer::observe(Observable*s)
{
    s->__register(this);//类似于注册回调函数,这里传递的是观察者地址。
    __subject=s;//观察者通过指针访问到它观察的对象
}
Observer::~Observer()
{
    __subject->__unregister(this);
}

被观察对象

//Observable.h
#ifndef __OBSERVABLE_H__
#define __OBSERVABLE_H__
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include "Observer.h"
class Observer;
class Observable
{
    public:
        Observable(){}
        virtual ~Observable(){}
        void __register(Observer *x);
        void __unregister(Observer *x);
        void notify();//通知观察者
        virtual void status(const std::string &s);//set状态
        virtual std::string status();//get状态
    private:
        std::vector<Observer*> __observers;//记录所有的观察者
    protected:
        std::string __status;
};
#endif
//Observable.cpp

#include "Observable.h"
#include "Observer.h"

void Observable::notify()
{
    for(int i=0;i<__observers.size();++i)//通知所有观察者
    {
        Observer * x = __observers[i];
        if(NULL!=x)
        {
            x->update();
        }
    }
}

void Observable::__register(Observer*x)
{
    __observers.push_back(x);
}

void Observable::__unregister(Observer *x)
{
    std::vector<Observer*>::iterator it = std::find(__observers.begin(),__observers.end(),x);
    if(it != __observers.end())//found!
    {
        std::swap(*it,__observers.back());
        __observers.pop_back();
    }
}

void Observable::status(const std::string &s)
{
    __status=s;
}
std::string Observable::status()
{
    return __status;
}

main函数

在main函数中,对观察者和被观察的对象分别派生类。

其中,观察者为订阅博客的人。
被观察对象为优快云博客的博主。

观察者订阅之后,当有博客更新,就推送给其观察者。

//main.cpp

#include "Observer.h"
#include "Observable.h"
class BlogObserver : public Observer//订阅博客的人
{
    private:
    std::string __name;
    public:
    BlogObserver(std::string name):__name(name){}
    virtual void update();
};

class Blog优快云 : public Observable//博主
{
    private:
        std::string __name;//blog name
    public:
        Blog优快云(std::string name ):__name(name){}
        ~Blog优快云(){}
        void status(const std::string &s);
        std::string status(); 
};


void Blog优快云::status(const std::string &s)//重写,更新博客
{
    __status="Blog Name: "+__name+" Content: "+s;

}

std::string Blog优快云::status()
{
    return __status;
}


void BlogObserver::update()//更新(收到消息)
{
    std::string status=__subject->status();
    std::cout<<status<<std::endl;
    std::cout<<__name<<" is notified"<<std::endl;
}
int main()
{
    Observer * p = new BlogObserver("SomeOne");//观察者1号
    Observer * q = new BlogObserver("SomeOne2");//观察者2号
    Observable *sub1= new Blog优快云("zhangxiao93") ;//博主

    sub1->status("UNIX Network Programming(1)");//博主更新博文

    //观察者订阅
    p->observe(sub1);
    q->observe(sub1);
    sub1->notify();//通知所有观察者

    delete p;
    delete q;
    delete sub1;
    return 0;
}

Makefile

PROGS = main

CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \
        *.lc *.lh *.bsdi *.sparc *.uw
all: ${PROGS}

CXXFLAGS= -Wall  -g
OBJ=main.o Observer.o Observable.o
LDFLAGS=



main: ${OBJ}
    ${CXX} ${CXXFLAGS} $^ -o $@   ${LDFLAGS}

clean:
    rm -f ${PROGS} core *.o

.PHONY: clean all

参考

1.《大话设计模式》
2.http://blog.youkuaiyun.com/wuzhekai1985/article/details/6674984
3.muduo源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值