C++ Observer设计模式的学习 (Boolan学习笔记第11周)

来源:互联网 发布:手机城市选择器插件js 编辑:程序博客网 时间:2024/05/22 02:31

本周学习了几种设计模式,包括Template, Strategy, Observer, Decorator和Bridge,觉得都有用。本文重点回顾一下Observer设计模式。

Observer设计模式主要应用在当目标对象的状态发生改变的时候,所有的依赖对象(也就是观察者对象)都将得到通知并自动更新。说到”通知”,有嵌入式背景的同学可能马上就会想到用polling和interrupt这两种方法,但我们这里说的设计模式是在应用层,跟底层的OS和hardware无关,其实完全是两个不同领域的东西。

这里要注意的是,目标对象发送通知时,无需指定观察者,通知会自动传播给已经订阅通知的观察者。目标对象并不知道谁是观察者。我们想象这样一个例子,假设有几百万个客户都订阅了一个微信公众号,这个公众号每天都发送一些八卦新闻。客户可以自己选择订阅或退订,公众号的任务就是发送新闻而已,所有的客户在它看来都一样,没有区别。它一发送新闻,那些客户就收到新闻了。这个例子就是一个观察者模式的实际运用。

观察者模式的结构描述如下图:
这里写图片描述

这里Subject和Observer之间是松耦合。Subject的Notify()里面会调用一个loop,遍历所有的观察者并调用它们的update()函数。在Subject看来所有的观察者都是一样的,它们的update()没有区别。Observer通过订阅/退订,可以决定要不要收到通知。

Observer设计模式在基于时间的UI框架中用的很多。一个具体例子如下:

class IProgress{public:    virtual void DoProgress(float value)=0;    virtual ~IProgress(){}};class FileSplitter{    string m_filePath;    int m_fileNumber;    List<IProgress*>  m_iprogressList; // 抽象通知机制,支持多个观察者public:    FileSplitter(const string& filePath, int fileNumber) :        m_filePath(filePath),         m_fileNumber(fileNumber){    }    void split(){        //1.读取大文件        //2.分批次向小文件中写入        for (int i = 0; i < m_fileNumber; i++){            //...            float progressValue = m_fileNumber;            progressValue = (i + 1) / progressValue;            onProgress(progressValue);//发送通知        }    }    void addIProgress(IProgress* iprogress){        m_iprogressList.push_back(iprogress);    }    void removeIProgress(IProgress* iprogress){        m_iprogressList.remove(iprogress);    }protected:    virtual void onProgress(float value){        List<IProgress*>::iterator itor=m_iprogressList.begin();        while (itor != m_iprogressList.end() )            (*itor)->DoProgress(value); //更新进度条            itor++;        }    }};class MainForm : public Form, public IProgress{    TextBox* txtFilePath;    TextBox* txtFileNumber;    ProgressBar* progressBar;public:    void Button1_Click(){        string filePath = txtFilePath->getText();        int number = atoi(txtFileNumber->getText().c_str());        ConsoleNotifier cn;        FileSplitter splitter(filePath, number);        splitter.addIProgress(this); //订阅通知        splitter.addIProgress(&cn); //订阅通知        splitter.split();        splitter.removeIProgress(this);    }    virtual void DoProgress(float value){        progressBar->setValue(value);    }};class ConsoleNotifier : public IProgress {public:    virtual void DoProgress(float value){        cout << ".";    }};

在这个例子中,FileSplitter是Subject, MainFrame和Console都是客户。FileSplitter切割文件的时候,会调用onProgress()函数。onProgress()就相当于上面图里面的Notify(),里面会遍历m_iprogressList,这个就是客户列表。客户通过splitter.addIProgress()来订阅通知。

另外要注意的是,如果订阅的客户多了,Subject里面的Notify()就会比较慢,变成系统的瓶颈。看来这个Observer模式也是有局限性的。

0 0
原创粉丝点击