观察者模式 Observer / Event

“组件协作”模式:

  • 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
  • 典型模式
  1. Template Method
  2. Observer / Event
  3. 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

posted @   double64  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示