观察者模式 Observer / Event
“组件协作”模式:
- 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
- 典型模式
- Template Method
- Observer / Event
- Strategy
动机(Motivation)
- 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
- 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
模式定义
定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。——《设计模式》GoF
单个观察者
个人感觉,类似于用接口类型封装的回调。
示例:
#include <iostream>
using namespace std;
class IProgress
{
public:
    virtual ~IProgress() {}
    virtual double DoProgress(double v) = 0;
};
//  发布者
class Translation
{
public:
    Translation(int factor, IProgress * iProgress)
    {
        m_Factor = factor;
        m_IProgress = iProgress;
    }
    virtual ~Translation() {}
    void DealSomeThing()
    {
        int factor;
        if (m_Factor <= 0) {
            factor = 2;
        }
        else {
            factor = 3;
        }
        if (m_IProgress != nullptr) {
            double restult = m_IProgress->DoProgress((double)factor);
            cout << "百分比:" << restult << "%" << endl;
        }
    }
private:
    IProgress *m_IProgress;
    int m_Factor;
};
// 订阅者 观察者
class Dosomething :public IProgress
{
public:
    Dosomething(double n) { m_num = n; }
    virtual  ~Dosomething() {};
    virtual double DoProgress(double v) override
    {
        return (v + m_num);
    }
    void DoThing()
    {
        Translation trans(1, this);
        trans.DealSomeThing();
    }
private:
    double m_num;
};
int main()
{
    Dosomething do_some_thing(12);
    do_some_thing.DoThing();
    getchar();
    return 0;
}
输出:
百分比:15%
多个观察者
用一个数据结构把接口引用存起来进行遍历管理。
使用接口的部分是相对稳定的,接口具体的实现应该是相对变化的比较多的。
代码:
#include <iostream>
#include <vector>
using namespace std;
class IProgress
{
public:
    virtual ~IProgress() {}
    virtual double DoProgress(double v) = 0;
};
// 发布者
class Translation
{
public:
    Translation(int factor)
    {
        m_Factor = factor;
    }
    virtual ~Translation() {}
    void DealSomeTrans()
    {
        // 模拟一些过程
        int factor;
        if (m_Factor <= 0) {
            factor = 2;
        }
        else {
            factor = 3;
        }
        if (m_IProgress.size() > 0) {
            for (int i = 0; i < m_IProgress.size(); i++) {
                double restult = m_IProgress[i]->DoProgress((double)factor);
                cout << "百分比:" << restult << "%" << endl;
            }
            
            // 用迭代器
           /* for (vector<IProgress *>::iterator itor = m_IProgress.begin(); itor != m_IProgress.end(); itor++) {
                double restult = (*itor)->DoProgress((double)factor);
                cout << "百分比:" << restult << "%" << endl;
            }*/
        }
    }
    void Add(IProgress* progress)
    {
        m_IProgress.push_back(progress);
    }
    void Remove(IProgress* progress)
    {
        vector<IProgress *>::iterator itor = m_IProgress.begin();
        while (itor != m_IProgress.end())
        {
            if (*itor == progress) {
                // 删除一个元素之后,迭代器已经指向了被删除元素的下一个元素
                itor = m_IProgress.erase(itor);
            }
            else {
                itor++;
            }
        }
    }
private:
    vector<IProgress *> m_IProgress;
    int m_Factor;
};
// 订阅者 观察者
class AddSomething :public IProgress
{
public:
    AddSomething(double n) { m_num = n; }
    virtual  ~AddSomething() {};
    virtual double DoProgress(double v) override
    {
        return (v + m_num);
    }
private:
    double m_num;
};
// 订阅者 观察者
class MultiSomething :public IProgress
{
public:
    MultiSomething(double n) { m_num = n; }
    virtual  ~MultiSomething() {};
    virtual double DoProgress(double v) override
    {
        return (v * m_num);
    }
private:
    double m_num;
};
int main()
{
    AddSomething addSome(5.0);
    MultiSomething multiSome(5.0);
    Translation trans(1);
    trans.Add(&addSome);
    trans.Add(&multiSome);
    trans.DealSomeTrans();
    cout << "-------" << endl;
    trans.Remove(&addSome);
    trans.DealSomeTrans();
    getchar();
    return 0;
}
输出:
百分比:8%
百分比:15%
-------
百分比:15%
类图

▲ 上面的示例代码中,没有拆分 Subject 和 ConcreteSubject 了,全部写在一起了。
要点总结
- 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。 // 独立的更改就是松耦合的意思。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
参考:GeekBand
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号