【设计模式】观察者模式及函数式编程的替代C++

本文介绍观察者模式以及使用函数式编程替代简单的策略模式。

观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

当对象间存在一对多关系时,则使用观察者模式(Observer

Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

简单来说,观察者模式需要多个对象观察同一个对象,被观察的对象称为Subject(主题),Subject需要完成观察者的注册(attach),注销(detach)和通知(notify)三个操作。

首先实现一个公共的Observer父类,这个父类只有一个纯虚函数,用来更新自身状态:

cpp 复制代码
struct Observer
{
public:
    virtual void update() = 0;
};

两个具体的类,实现 update 函数:

cpp 复制代码
struct ConcreteObserver : Observer
{
public:
    void update() override
    {
        std::cout << "State updated!" << std::endl;
    }
};

struct ConcreteObserver2 : Observer
{
public:
    void update() override
    {
        std::cout << "State updated! 2" << std::endl;
    }
};

接下来实现被观察者公共类,包含添加、删除、通知所有观察者三个接口:

cpp 复制代码
struct Subject
{
public:
    virtual void attach(Observer *observer) = 0;
    virtual void detach(Observer *observer) = 0;
    virtual void notify() = 0;
};

具体的被观察者类,实现这三个接口:

cpp 复制代码
struct ConcreteSubject : Subject
{
public:
    void attach(Observer *observer) override
    {
        observers.push_back(observer);
    }

    void detach(Observer *observer) override
    {
        for (auto it = observers.begin(); it != observers.end(); it++)
        {
            if (*it == observer)
            {
                observers.erase(it);
                break;
            }
        }
    }

    void notify() override
    {
        for (auto &observer : observers)
        {
            observer->update();
        }
    }

private:
    std::vector<Observer *> observers;
};

测试代码如下:

cpp 复制代码
int main()
{
    ConcreteSubject subject;
    ConcreteObserver observer1;
    ConcreteObserver2 observer2;

    subject.attach(&observer1);
    subject.attach(&observer2);

    subject.notify();

    subject.detach(&observer1);

    subject.notify();
}

函数式编程下的观察者模式

首先需要介绍下C语言的函数指针。所谓函数指针即定义一个指向函数的指针变量,格式如下:

cpp 复制代码
typedef void (*Callback)();

这样就定义了一个变量名为Callback的指针变量,指向一个参数为void,返回值也为void的函数。我们用这种指针变量,就能将整个观察者类改成函数。

两个观察者函数:

cpp 复制代码
void callback1()
{
    std::cout << "State updated!" << std::endl;
}

void callback2()
{
    std::cout << "State updated! 2" << std::endl;
}

被观察的类。原先调用观察者类的地方全部改为函数调用:

cpp 复制代码
struct ConcreteSubject
{
public:
    void attach(Callback callback)
    {
        observers.push_back(callback);
    }

    void detach(Callback callback)
    {
        for (auto it = observers.begin(); it != observers.end(); it++)
        {
            if (*it == callback)
            {
                observers.erase(it);
                break;
            }
        }
    }

    void notify()
    {
        for (auto &observer : observers)
        {
            observer();
        }
    }

private:
    std::vector<Callback> observers;
};

观察者模式与回调

我给函数指针起名为Callback。事实上,当只有一个观察者的时候,观察者模式的机制就等同于回调模式。因此可以认为,回调模式是一种特殊的观察者模式。

相关推荐
书院门前细致的苹果12 分钟前
设计模式大全:单例、工厂模式、策略模式、责任链模式
设计模式·责任链模式·策略模式
MZ_ZXD0011 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
A星空1232 小时前
一、Linux嵌入式的I2C驱动开发
linux·c++·驱动开发·i2c
凡人叶枫2 小时前
C++中智能指针详解(Linux实战版)| 彻底解决内存泄漏,新手也能吃透
java·linux·c语言·开发语言·c++·嵌入式开发
会叫的恐龙3 小时前
C++ 核心知识点汇总(第六日)(字符串)
c++·算法·字符串
小糯米6013 小时前
C++顺序表和vector
开发语言·c++·算法
独望漫天星辰3 小时前
C++ 多态深度解析:从语法规则到底层实现(附实战验证代码)
开发语言·c++
王老师青少年编程4 小时前
2024年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第3题)
c++·题解·真题·csp·信奥赛·csp-s·提高组
凡人叶枫4 小时前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
CSDN_RTKLIB4 小时前
使用三方库头文件未使用导出符号情景
c++