设计模式(四) —— 观察者模式/发布订阅模式,c和c++示例代码

这篇具有很好参考价值的文章主要介绍了设计模式(四) —— 观察者模式/发布订阅模式,c和c++示例代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

往期地址:

  • 设计模式(一)——简单工厂模式
  • 设计模式(二)——策略模式
  • 设计模式(三)——装饰模式

本期主题:

使用c和c++代码,讲解观察者模式、发布订阅模式



1.什么是发布-订阅模式

  • 发布-订阅模式是一种行为设计模式,它允许多个对象通过事件的发布和订阅来进行通信;
  • 在这种模式中,发布者(又称为主题)负责发布事件,而订阅者(也称为观察者)则通过订阅主题来接收这些事件;
  • 这种模式使得应用程序的不同部分能够松散耦合,并且可以动态地添加或删除订阅者;

2.实例

2.1 场景

A、B、C、D 4个人都订阅了报纸,所以希望当有新报纸来时,通知到这4个人,并且订阅的人可能后面会越来越多,也可能减少,需要有一个机制能够方便的添加、删除订阅的人。因此需求如下:

  1. 当有新报纸时,需要通知到所有订阅的人;
  2. 订阅的人可以方便的添加、修改、删除;

2.2 代码设计

设计思路:
发布者(也称为主题),负责:

  • 发布事件,把消息推送到所有的订阅者
  • 负责管理(增加、删除)订阅者

订阅者负责:

  • 具体的发布消息的实现

示例代码:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

// 前向声明
class Publisher;
class Subscriber;

// 订阅者接口
class Subscriber {
public:
    virtual void update(const string& message) = 0;
};

// 发布者类
class Publisher {
public:
    // 添加订阅者
    void subscribe(Subscriber* subscriber) {
        subscribers_.push_back(subscriber);
    }

    // 删除订阅者
    void unsubscribe(Subscriber* subscriber) {
        for (auto it = subscribers_.begin(); it != subscribers_.end(); ++it) {
            if (*it == subscriber) {
                subscribers_.erase(it);
                break;
            }
        }
    }

    // 发送消息给所有订阅者
    void notify(const string& message) {
        for (auto subscriber : subscribers_) {
            subscriber->update(message);
        }
    }

private:
    vector<Subscriber*> subscribers_;
};

// 订阅者1
class Subscriber1 : public Subscriber {
public:
    virtual void update(const string& message) {
        cout << "Subscriber1 received message: " << message << endl;
    }
};

// 订阅者2
class Subscriber2 : public Subscriber {
public:
    virtual void update(const string& message) {
        cout << "Subscriber2 received message: " << message << endl;
    }
};

int main() {
    Publisher publisher;
    Subscriber1 subscriber1;
    Subscriber2 subscriber2;

    // 添加订阅者
    publisher.subscribe(&subscriber1);
    publisher.subscribe(&subscriber2);

    // 发送消息
    publisher.notify("Hello, world!");

    // 删除订阅者
    publisher.unsubscribe(&subscriber1);

    // 发送另一条消息
    publisher.notify("Goodbye!");

    return 0;
}
//测试结果:
$ ./a.out
Subscriber1 received message: Hello, world!
Subscriber2 received message: Hello, world!
Subscriber2 received message: Goodbye!


2.3 代码的优化

有些场景是我们并不想一有消息就通知所有的订阅者,我们希望在添加订阅者时,就知道这个订阅者需要订阅哪种消息,这样无关的消息就不会推送给他 ,因此我们对代码进行修改,在发布者类中添加了一个Map,来进行事件的管理:

#include <iostream>
#include <vector>
#include <unordered_map>
#include <string>

using namespace std;

// 前向声明
class Publisher;
class Subscriber;

// 订阅者接口
class Subscriber {
public:
    virtual void update(const string& topic, const string& message) = 0;
};

// 发布者类
class Publisher {
public:
    // 添加订阅者
    void subscribe(const string& topic, Subscriber* subscriber) {
        subscribers_[topic].push_back(subscriber);
    }

    // 删除订阅者
    void unsubscribe(const string& topic, Subscriber* subscriber) {
        auto it = subscribers_.find(topic);
        if (it != subscribers_.end()) {
            auto& subscribers = it->second;
            for (auto it2 = subscribers.begin(); it2 != subscribers.end(); ++it2) {
                if (*it2 == subscriber) {
                    subscribers.erase(it2);
                    break;
                }
            }
        }
    }

    // 发送消息给所有订阅者
    void notify(const string& topic, const string& message) {
        auto it = subscribers_.find(topic);
        if (it != subscribers_.end()) {
            auto& subscribers = it->second;
            for (auto subscriber : subscribers) {
                subscriber->update(topic, message);
            }
        }
    }

private:
    unordered_map<string, vector<Subscriber*>> subscribers_;
};

// 订阅者1
class Subscriber1 : public Subscriber {
public:
    virtual void update(const string& topic, const string& message) {
        cout << "Subscriber1 received message: " << message << " on topic: " << topic << endl;
    }
};

// 订阅者2
class Subscriber2 : public Subscriber {
public:
    virtual void update(const string& topic, const string& message) {
        cout << "Subscriber2 received message: " << message << " on topic: " << topic << endl;
    }
};

int main() {
    Publisher publisher;
    Subscriber1 subscriber1;
    Subscriber2 subscriber2;

    // 添加订阅者
    publisher.subscribe("topic1", &subscriber1);
    publisher.subscribe("topic2", &subscriber2);

    // 发送消息
    publisher.notify("topic1", "Hello, world!");

    // 删除订阅者
    publisher.unsubscribe("topic1", &subscriber1);

    // 发送另一条消息
    publisher.notify("topic1", "Goodbye!");
    publisher.notify("topic2", "Hello, again!");

    return 0;
}

//测试结果:
$ ./a.out
Subscriber1 received message: Hello, world! on topic: topic1
Subscriber2 received message: Hello, again! on topic: topic2

3.用C语言来实现

我们采用了链表来管理订阅者。文章来源地址https://www.toymoban.com/news/detail-416162.html

  • 每个事件类型对应一个订阅者链表,每个链表节点包含了一个回调函数和指向下一个节点的指针;
  • 在订阅和取消订阅时,我们需要遍历对应的链表,找到要添加或删除的节点,订阅时添加上对应的事件和回调处理;
  • 在通知时,通知事件和具体的消息;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_EVENT_TYPE 10
#define MAX_EVENT_SIZE 100

typedef enum {
    EVENT_TYPE_1,
    EVENT_TYPE_2,
    EVENT_TYPE_3,
    EVENT_TYPE_4,
    EVENT_TYPE_5,
    EVENT_TYPE_6,
    EVENT_TYPE_7,
    EVENT_TYPE_8,
    EVENT_TYPE_9,
    EVENT_TYPE_10,
    EVENT_TYPE_MAX
} EventType;

typedef struct {
    char data[MAX_EVENT_SIZE];
} Event;

typedef struct SubscriberNode {
    void (*callback)(Event *);
    struct SubscriberNode *next;
} SubscriberNode;

typedef struct {
    SubscriberNode *head;
    SubscriberNode *tail;
} SubscriberList;

SubscriberList subscriber_list[EVENT_TYPE_MAX] = {{NULL, NULL}};

void publisher_subscribe(EventType event_type, void (*callback)(Event *)) {
    SubscriberNode *node = (SubscriberNode *)malloc(sizeof(SubscriberNode));
    node->callback = callback;
    node->next = NULL;

    SubscriberList *list = &subscriber_list[event_type];
    if (!list->head) {
        list->head = list->tail = node;
        return;
    }

    list->tail->next = node;
    list->tail = node;
}

void publisher_unsubscribe(EventType event_type, void (*callback)(Event *)) {
    SubscriberList *list = &subscriber_list[event_type];
    if (!list->head) {
        return;
    }

    SubscriberNode *cur_node = list->head;
    SubscriberNode *prev_node = NULL;
    while (cur_node) {
        if (cur_node->callback == callback) {
            if (prev_node) {
                prev_node->next = cur_node->next;
            } else {
                list->head = cur_node->next;
            }
            if (!cur_node->next) {
                list->tail = prev_node;
            }
            free(cur_node);
            return;
        }
        prev_node = cur_node;
        cur_node = cur_node->next;
    }
}

void publisher_notify(EventType event_type, Event *event) {
    SubscriberList *list = &subscriber_list[event_type];
    SubscriberNode *cur_node = list->head;

    while (cur_node) {
        cur_node->callback(event);
        cur_node = cur_node->next;
    }
}

void subscriber_callback1(Event *event) {
    printf("Subscriber 1 received event: %s\n", event->data);
}

void subscriber_callback2(Event *event) {
    printf("Subscriber 2 received event: %s\n", event->data);
}

int main() {
    Event event1 = {"Event 1 data"};
    Event event2 = {"Event 2 data"};

    publisher_subscribe(EVENT_TYPE_1, subscriber_callback1);
    publisher_subscribe(EVENT_TYPE_1, subscriber_callback2);
    publisher_notify(EVENT_TYPE_1, &event1);

    printf("\n");

    publisher_unsubscribe(EVENT_TYPE_1, subscriber_callback2);
    publisher_notify(EVENT_TYPE_1, &event2);

    return 0;
}

//测试结果:
$ ./a.out
Subscriber 1 received event: Event 1 data
Subscriber 2 received event: Event 1 data

Subscriber 1 received event: Event 2 data

到了这里,关于设计模式(四) —— 观察者模式/发布订阅模式,c和c++示例代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • C++之观察者模式(发布-订阅)

    C++之观察者模式(发布-订阅)

    目录 模式简介 介绍 优点 缺点 代码实现 场景说明 实现代码 运行结果 观察者模式( Observer Pattern ) ,也叫我们熟知的 发布-订阅模式。 它是一种 行为型模式。 介绍 观察者模式主要关注的是对象的一对多的关系, 也就是多个对象依赖于一个对象,当该对象的 状态发生改变

    2024年02月15日
    浏览(49)
  • 观察者模式、中介者模式和发布订阅模式

    观察者模式、中介者模式和发布订阅模式

    观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新 观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯 例如生活中,我们可以用报

    2024年02月15日
    浏览(49)
  • JavaScript 简单实现观察者模式和发布-订阅模式

    JavaScript 简单实现观察者模式和发布-订阅模式

    大家好,我是南木元元,热衷分享有趣实用的文章。今天来聊聊设计模式中常用的观察者模式和发布-订阅模式。 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。 如何理解这句话呢?来举个生活中的例子

    2024年02月12日
    浏览(315)
  • 从Vue层面 - 解析发布订阅模式和观察者模式区别

    从Vue层面 - 解析发布订阅模式和观察者模式区别

    观察者模式和发布订阅模式作为日常开发中经常使用到的模式,我一直不能做到很好的区分。最近在看Vue的源码,里面设计到了观察者模式,比较感兴趣,就去学习了下,这里做个总结吧。 基于一个 事件中心 ,接收通知的对象是订阅者,需要先订阅某个事件,触发事件的对

    2024年02月15日
    浏览(45)
  • 【JavaScript】手撕前端面试题:寄生组合式继承 | 发布订阅模式 | 观察者模式

    🧑‍💼个人简介:大三学生,一个不甘平庸的平凡人🍬 🖥️ NodeJS专栏:Node.js从入门到精通 🖥️ 博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述) 🖥️ TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结) 👉

    2023年04月08日
    浏览(50)
  • 设计模式——观察者模式

    设计模式——观察者模式

    观察者模式可以分为观察者和被观察者,观察者通过注册到一个被观察者中,也可视为订阅,当被观察者的数据发生改变时,会通知到观察者,观察者可以据此做出反应。 可以类比订阅报纸,报社就是被观察者,订阅者就是观察者,订阅者通过订阅报纸与报社建立联系,而报

    2024年02月15日
    浏览(12)
  • 【设计模式】观察者模式

    【设计模式】观察者模式

    观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。 Subject:抽象主题(被观察者

    2024年02月13日
    浏览(10)
  • 设计模式---观察者模式

    1,概念         属于行为模式的一种,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一对象主题对象,这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。 在观察者模式中有如下角色: Subject:抽象主题(抽象被观察者),

    2024年02月15日
    浏览(10)
  • 设计模式:观察者模式

    定义 观察者模式(Observer Pattern)是一种行为设计模式,允许一个对象(称为“主题”或“可观察对象”)维护一组依赖于它的对象(称为“观察者”),当主题的状态发生变化时,会自动通知所有观察者对象。 应用场景 观察者模式适用于以下场景: 联动反应 :当一个对象

    2024年04月08日
    浏览(14)
  • 设计模式-观察者模式

    观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者

    2024年02月15日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包