观察者模式——C++实现

观察者模式定义了一对多的依赖关系,当被观察的对象状态改变时,所有观察者都会得到通知并自动更新。例如,班级里班长监视老师到来,通知看小说的同学。在VS软件中,点击运行后的各种响应也是观察者模式的应用。本文通过C++代码示例,展示了如何实现观察者模式,涉及继承、抽象类、纯虚函数和动态绑定等概念。

定义:

    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个通知对象。当这个通知对象状态发生改变时,会告知它的所有观察者对象自动更新,进而做出相应的反映。

举个例子:

    在一个班级里,自习课的时候我们偷偷看小说,这时候又很害怕老师突然来了,于是我们总是让坐窗户边没有看小说也没看书的班长替我们看着,老师来了就通知我们这些看小说的同学。然后我们就赶紧收起小说,假装在认真学习的样子。这就相当于是一个观察者模式,其中,班长相当于通知者,我们这些看小说的同学相当于是观察者,班长(通知者)发现老师来了,就通知我们(观察者)所有看小说的人,然后我们分别执行自己的处理方法(藏小说、或者扔给同桌)

实际应用:

    例如在我们的VS软件中,点击运行以后,会有好几个控件跟着做出反映,比如命令窗口打开、工具箱隐藏等,这就是一个观察者模式 (还可以借助委托和事件机制来解决通知者类对观察者类的依赖)

结构图:


示例代码:

//以《大话设计模式》中的前台(通知者)、员工(观察者)之间的消息通知机制为例,只不过这里是用C++写的,而书中是用C#写的

#include<iostream>

#include<string>

#include<list>

using namespace std;

class Subject;

/****************************观察者***************************/

class Observer{
    
public:
    
    Observer(string name, Subject* Sub) :name(name), Sub(Sub){ }
    
    virtual ~Observer(){ }
    
    virtual void update()=0;     //观察者收到通知者状态信息改变以后需要做的响应函数
    
protected:
    
    string name;
    
    Subject* Sub;     //观察者类有一个指向通知者的指针,用以调用通知者类里的状态改变信息接口,总要知道发生了什么吧
    
};

//看股票的观察者们

class StockObserver :public Observer{
    
public:
    
    StockObserver(string name, Subject* Sub) :Observer(name, Sub){ }
    
    ~StockObserver(){ }
    
    void update();
    
};

//玩游戏的观察者们

class GameObserver :public Observer{
    
public:
    
    GameObserver(string name, Subject* Sub) :Observer(name, Sub){ }
    
    ~GameObserver(){ }
    
    void update();
    
};

//看球赛的观察者们

class NBAObserver :public Observer{
    
public:
    
    NBAObserver(string name, Subject* Sub) :Observer(name, Sub){ }
    
    ~NBAObserver(){ }
    
    void update();
    
};

/****************************通知者***************************/

class Subject{
    
public:
    
    Subject() { }
    
    virtual ~Subject(){ }
    
    virtual void Attach(Observer* observer) = 0;   //将观察者加入到自己的名单里,当状态改变以后只会通知在自己名单里的观察者们
    
    virtual void Detach(Observer* observer) = 0;  //将观察者从自己的名单里删除
    
    virtual void Notify() = 0;       //通知函数,通知观察者们做出响应
    
    string action;
    
};

class Scretary :public Subject{
    
public:
    
    Scretary(){ }
    
    ~Scretary(){ }
    
    void Attach(Observer* observer);
    
    void Detach(Observer* observer);
    
    void Notify();
    
private:
    
    list<Observer* > observers;     //用于保存需要通知的观察者们的指针,不能是对象,想想为什么
    
};

void Scretary::Attach(Observer* observer){
    
    observers.push_back(observer);
    
}

void Scretary::Detach(Observer* observer){
    
    observers.remove(observer);
    
}

void Scretary::Notify(){
    
    list<Observer* >::iterator iter = observers.begin();
    
    while (iter != observers.end()){
        
        (*iter)->update();    //回调
        
        ++iter;
        
    }
    
}

//注,以下这一部分必须写在上述通知者代码之后,不然会报错:使用了未定义类型Subject

void StockObserver::update(){
    
    cout << name << "收到消息:" << Sub->action << endl;
    
    if (Sub->action == "老板来了")
        
        cout << "关闭股票页面" << endl;
    
}

void GameObserver::update(){
    
    cout << name << "收到消息:" << Sub->action << endl;
    
    if (Sub->action == "老板来了")
        
        cout << "关闭游戏页面" << endl;
    
}

void NBAObserver::update(){
    
    cout << name << "收到消息:" << Sub->action << endl;
    
    if (Sub->action == "老板来了")
        
        cout << "关闭游戏页面" << endl;
    
}

int main(){
    
    Subject* Sub = new Scretary();    //创建通知者
    
    /************创建观察者**********************************/
    
    Observer* ob1 = new StockObserver("zhangsan", Sub);
    
    Observer* ob2 = new NBAObserver("lisi", Sub);
    
    Observer* ob3 = new GameObserver("wang", Sub);
    
    /*************将指向观察者的指针加入到通知者的通知名单里(不然怎么知道通知谁呢)*******/
    
    Sub->Attach(ob1);
    
    Sub->Attach(ob2);
    
    Sub->Attach(ob3);
    
    Sub->action = "老板来了";  //发现事件发生,即状态改变
    
    Sub->Notify();  //通知观察者们
    
    Sub->action = "吃饭了";
    
    Sub->Notify();
    
    Sub->Detach(ob2);  //将ob2这个观察者从自己的通知名单里移除,之后将不会通知到他
    
    Sub->action = "老板又来了";
    
    Sub->Notify();
    
    return 0;
    
}

运行结果:


涉及到的概念:继承、抽象类、纯虚函数、动态绑定、链表list

参考书籍:《大话设计模式》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值