设计模式-观察者模式 C++

设计模式-观察者模式 C++,第1张


一、简介

观察者模式属于行为型模式。


意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。


主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。



二、建立和使用观察者模式 1、建立观察者组件

首先,我们有一个被观察的对象A,和观察对象A的观察者对象B、C、D。


则我们需要

1)、声明一个抽象观察者类,类中声明观察者响应函数;

2)、被观察对象A需要一个成员数据,观察者对象的指针列表_observerList,用于存放观察者们的指针。


并提供在_observerList中添加、移除观察者指针的接口,即在_observerList中进行增删的方法。


同时还可能需要要定义被观察事件的触发函数;

3)、观察者对象B、C、D需要继承一抽象观察者类,并实现响应函数;

2、使用观察者组件

1)首先,在B、C、D的对象中,要先获取到A的指针,并调用A的添加观察者指针接口,把this指针保存进A的_observerList中;

2)然后,当A中被关注的事件发生时,A根据_observerList存储的指针依次调用响应函数;

3)B、C、D分别对观察的事件进行响应;


三、观察者模式使用实例

假设数学教师A预计明天进行一场数学考试,同时体育老师,学生A,学生B和关注了数学考试的事件。


如果将有数学考试发生时,体育老师,学生A,学生B都会收到通知。


1、首先,我们根据目前情况,先创建观察者组件 1)创建观察者抽象类EventObserver
class EventObserver
{
public:
    virtual ~EventObserver() {}

    virtual void MathExamEvent(bool isMorning) = 0;
};

        其中MathExamEvent就是定义的响应函数,此函数可以声明为纯虚函数也可以声明为虚函数,如果EventObserver有子类并不需要观察MathExamEvent事件,同时也不打算实现MathExamEvent,则可以声明为虚函数。


2)创建被观察对象。


此处我们创建数学老师类

class MathTeacher
{
public:
    //添加观察者
    void addObserver(EventObserver* ob)
    {
        _mtx.lock();

        //排重处理
        if (_observerList.end() == std::find(_observerList.begin(), _observerList.end(), ob))
        {
            _observerList.push_back(ob);
        }

        _mtx.unlock();
    }

    //移除观察者
    void RemoveObserver(EventObserver* ob)
    {
        _mtx.lock();
        vector::iterator it = std::find(_observerList.begin(), _observerList.end(), ob);

        if (_observerList.end() != it)
        {
            _observerList.erase(it);
        }

        _mtx.unlock();
    }

    //数学考试
    void MathExam(bool isMorning)
    {
        cout << "明天将有一场数学考试!" << endl;

        //通知各个观察者这场考试
        _mtx.lock();

        for (auto it : _observerList)
        {
            it->MathExamEvent(isMorning);
        }

        _mtx.unlock();
    }

    MathTeacher() : _observerList(), _mtx() {}

private:
    vector _observerList;
    std::mutex _mtx; //如果是多线程编程,需要对_observerList加锁保护
};

结合上诉代码,我们可以对应到被观察类的基本组件如下:

观察者对象的指针列表:_observerList

添加、移除观察者指针的接口:addObserver、RemoveObserver

被观察事件的触发函数:MathExam

3)创建观察者实现类,需要继承观察者抽象类EventObserver,实现对MathExamEvent的响应。


此处,我们声明体育老师、学生A、B三个类

//体育老师类
class PETeacher : public EventObserver
{
    virtual void MathExamEvent(bool isMorning)
    {
        cout << "我是体育老师,我了解到明天将有一场数学考试。


" << endl; } }; //学生A类 class StudentA: public EventObserver { public: StudentA() {} StudentA(MathTeacher& mathTeacher) { mathTeacher.addObserver(this); } virtual void MathExamEvent(bool isMorning) { cout << "我是小A:"; Study(); } private: void Study() { cout << "开始认真学习!" << endl; } }; //学生B类 class StudentB : public EventObserver { public: StudentB() {} StudentB(MathTeacher& mathTeacher) { mathTeacher.addObserver(this); } virtual void MathExamEvent(bool isMorning) { cout << "我是小B:"; if (!isMorning) { Play(); } Study(); } private: void Study() { cout << "开始认真学习!" << endl; } void Play() { cout << "开始玩耍!" << endl; } };

可见,三个类都会数学考试事件MathExamEvent做出了实现,其中体育老师并没有做出响应,两位学生对这场考试分别有自己的对策。


学生A打算立刻学习,准备考试;学生B认为如果考试在下午,可以先玩耍一会儿。


【注意】

        一般情况下,我们要避免各观察者类在观察事件响应函数中做太多的事情,已防止阻塞对其他观察者响应函数的调用和触发函数的继续运行。


如果某一观察者类的响应确实十分繁琐,必要情况下我们可以抛线程执行。


        比如,以上诉考试事件为例,因为“数学老师”是依次通知各观察者的,假如通知“体育老师”的时候,体育老师为了详细了解这场考试的情况,和“数学老师”聊了大半天并当场做出一大堆计划,则数学老师资源无法释放,会妨碍学生A,B得到这场考试的通知,同时数学老师也无法做其他事情。


此时,体育老师可以先停止和数学老师的沟通,释放数学老师后,自己做出处理。


见下列代码

体育老师需要做出计划

//体育老师类
class PETeacher : public EventObserver
{
    virtual void MathExamEvent(bool isMorning)
    {
        cout << "我是体育老师,我了解到明天将有一场数学考试。


" << endl; DoPlan(); } private: void DoPlan() { cout << "体育老师:结合相关信息,做出上课计划!" << endl; int plan = 100; for (int i = 0; i < 100; i++) { cout << "体育老师:计划" << i << "开始" << endl; } } };

由于计划十分繁琐,我们可以抛线程执行,不阻塞主线程

//体育老师类
class PETeacher : public EventObserver
{
public:
    virtual void MathExamEvent(bool isMorning)
    {
        cout << "我是体育老师,我了解到明天将有一场数学考试。


" << endl; //抛线程执行DoPlan threadObj = new thread(PETeacher::DoPlan); } static void DoPlan() { cout << "体育老师:结合相关信息,做出上课计划!" << endl; int plan = 100; for (int i = 0; i < 100; i++) { cout << "体育老师:计划" << i << "开始" << endl; } } PETeacher() : threadObj(nullptr) {} ~PETeacher() { if (nullptr != threadObj) { delete threadObj; threadObj = nullptr; } } private: std::thread* threadObj; };

2、观察者创建完毕,接下来展示的是对观察者的使用代码
int main()
{
    //创建实例
    MathTeacher mathTeacher;

    PETeacher peTeacher;
    //体育老师构造后,调用数学老师的addObserver方法添加观察者
    mathTeacher.addObserver(&peTeacher);

    //构造函数中添加观察者
    StudentA stdA(mathTeacher);
    StudentB stdB(mathTeacher);

    //数学老师计划组织数学考试
    mathTeacher.MathExam(true);

    system("pause");
    return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/569704.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存