在北京建网站,org后缀做网站行,建设网站不显示添加白名单,南宁做网站哪家好【设计模式】如何用C实现观察者模式【发布订阅机制】
一、问题背景
代码质量影响生活质量。最近工作中频繁接触各种设计模式#xff0c;深刻体会到优秀的设计模式不仅能显著降低后续维护的压力#xff0c;还能提升开发效率。观察者模式作为一种降低耦合度、提高扩展性的利器…【设计模式】如何用C实现观察者模式【发布订阅机制】
一、问题背景
代码质量影响生活质量。最近工作中频繁接触各种设计模式深刻体会到优秀的设计模式不仅能显著降低后续维护的压力还能提升开发效率。观察者模式作为一种降低耦合度、提高扩展性的利器其设计模式思想让人受益匪浅。
过去曾读过一本《练习的心态》书中提出了这样的问题当我们专注于过程时往往会偏离目标越专注离目标也就越远当我们关注目标时要么无法专注于过程要么因目标与现实的差距而产生放弃的念头。
如何把握过程与目标的关系也许需要我们用一种观察者的智慧和心态即同时使用两个视角来思考
第一种视角作为被观察者允许自身专注沉浸于过程最好进入心流状态。第二种视角作为观察者观察者观察沉浸于过程的执行者时常检查执行者是否偏离目标然后提醒执行者调整策略。
当掌握这两种视角后做到极致的情况下自身始终存在一种理性的观察者视角当自身愤怒时观察者能提供一种理性的视角以避免行为造成无法接受的后果。如果能做到这一点仅仅是愤怒的话又有何不可呢。
观察者模式中这两种视角是低耦合的而作为普通人难免经常会将两种视角混淆在一起。
”破山中贼易破心中贼难“要让心中始终存在一种理性的智慧也许还需要在事上学、心上练。把握人性的度量从而实现“从心所欲而不逾矩”的理想人格。
二、什么是观察者模式
观察者模式Observer Pattern是一种常见的设计模式属于行为型模式。它定义了一种一对多的依赖关系使得当一个对象的状态发生改变时其所有依赖对象观察者都会自动收到通知并更新。这种模式常用于事件驱动的系统。
观察者模式的核心概念
被观察者Subject也称为发布者它维护着一个观察者列表当它的状态发生变化时会通知所有观察者。观察者Observer也称为订阅者它订阅了某个被观察者当被观察者状态发生变化时它会收到通知并执行相应的操作。
三、观察者模式工作原理 注册观察者 观察者向被观察者注册把自己添加到被观察者的观察者列表中。 状态改变 被观察者的状态发生变化。 通知观察者 被观察者遍历观察者列表依次通知所有注册的观察者。 更新 观察者收到通知后根据自己的逻辑进行更新。
四、为什么使用观察者模式 低耦合 被观察者和观察者之间是低耦合的它们之间不需要知道对方的具体实现细节。 可扩展性 可以动态地增加或删除观察者而不需要修改被观察者或其他观察者的代码。 复用性 观察者模式可以被应用于各种场景提高代码的复用性。
五、实现步骤
以发布订阅为例需要实现以下三个组件
Publisher用于发布订阅事件承担了观察者模式中的Subject的状态改变功能。TopicServer用于中心化管理Topic订阅事件和Subscriber观察者列表承担了中的Subject的通知功能。Subscriber用于订阅Topic当发布者Publisher发布消息时订阅服务器TopicServer会通知所有订阅该Topic的订阅者Subscriber。
1. 订阅者类Subscriber
./subscribe/Subscribe.h
#ifndef SUBSCRIBE_H
#define SUBSCRIBE_H
#include string
namespace Observer
{class Subscriber{public:virtual ~Subscriber() default;virtual void Update(const std::string topic, const std::string message) 0;};
}
#endif./subscribe/SubscribeImpl.h
#ifndef SUBSCRIBEIMPL_H
#define SUBSCRIBEIMPL_H
#include Subscriber.h
namespace Observer
{class SubscriberImpl : public Subscriber{public:explicit SubscriberImpl(const std::string subscriberName);~SubscriberImpl() override;void Update(const std::string topic, const std::string message) override;private:std::string m_name;};
}
#endif./subscribe/SubscribeImpl.cpp
#include SubscriberImpl.h
#include iostream
using namespace Observer;SubscriberImpl::SubscriberImpl(const std::string subscriberName) : m_name(subscriberName) {}SubscriberImpl::~SubscriberImpl() {}void SubscriberImpl::Update(const std::string topic, const std::string message)
{std::cout Subscriber [ m_name ] received message on topic [ topic ]: message std::endl;
}2. 发布订阅中心类TopicServer
./topicServer/TopicServer.h
#ifndef TOPICSERVER_H
#define TOPICSERVER_H
#include string
#include memory
#include Subscriber.h
namespace Observer
{class TopicServer{public:virtual ~TopicServer() default;virtual void Subscribe(const std::string topic, std::shared_ptrSubscriber subscriber) 0;virtual void Unsubscribe(const std::string topic, std::shared_ptrSubscriber subscriber) 0;virtual void Notify(const std::string topic, const std::string message) 0;};
}
#endif./topicServer/TopicServerImpl.h
#ifndef TOPICSERVERIMPL_H
#define TOPICSERVERIMPL_H
#include TopicServer.h
#include unordered_map
#include vector
namespace Observer
{class TopicServerImpl : public TopicServer{public:explicit TopicServerImpl();~TopicServerImpl() override;void Subscribe(const std::string topic, std::shared_ptrSubscriber subscriber) override;void Unsubscribe(const std::string topic, std::shared_ptrSubscriber subscriber) override;void Notify(const std::string topic, const std::string message) override;private:std::unordered_mapstd::string, std::vectorstd::shared_ptrSubscriber m_topicSubscriber;};
}
#endif./topicServer/TopicServerImpl.cpp
#include TopicServerImpl.h
#include algorithm
using namespace Observer;TopicServerImpl::TopicServerImpl() {}TopicServerImpl::~TopicServerImpl() {}void TopicServerImpl::Subscribe(const std::string topic, std::shared_ptrSubscriber subscriber)
{m_topicSubscriber[topic].push_back(subscriber);
}void TopicServerImpl::Unsubscribe(const std::string topic, std::shared_ptrSubscriber subscriber)
{auto subscribersList m_topicSubscriber[topic];auto itBegin std::remove(subscribersList.begin(), subscribersList.end(), subscriber);subscribersList.erase(itBegin, subscribersList.end());if (subscribersList.size() 0) {m_topicSubscriber.erase(topic);}
}void TopicServerImpl::Notify(const std::string topic, const std::string message)
{if (m_topicSubscriber.contains(topic)) {for (auto subscriber : m_topicSubscriber[topic]) {subscriber-Update(topic, message);}}
}3. 发布者类Publisher
./publisher/Publisher.h
#ifndef PUBLISHER_H
#define PUBLISHER_H
#include string
namespace Observer
{class Publisher{public:virtual ~Publisher() default;virtual void PublishMessage(const std::string topic, const std::string message) 0;};
}
#endif
/publisher/PublisherImpl.h
#ifndef PUBLISHERIMPL_H
#define PUBLISHERIMPL_H
#include Publisher.h
#include TopicServer.h
#include memory
namespace Observer
{class PublisherImpl : public Publisher{public:explicit PublisherImpl(std::shared_ptrTopicServer topicServer);~PublisherImpl() override;void PublishMessage(const std::string topic, const std::string message) override;private:std::shared_ptrTopicServer m_server;};
}
#endif
/publisher/PublisherImpl.cpp
#include PublisherImpl.h
using namespace Observer;PublisherImpl::PublisherImpl(std::shared_ptrTopicServer topicServer) : m_server(topicServer) {}PublisherImpl::~PublisherImpl() {}void PublisherImpl::PublishMessage(const std::string topic, const std::string message) {m_server-Notify(topic, message);
}4. main函数调用
./main.cpp
#include PublisherImpl.h
#include TopicServerImpl.h
#include SubscriberImpl.h
namespace {constexpr std::string TOPICA {TopicA};constexpr std::string TOPICB {TopicB};
}
using namespace Observer;
int main()
{std::shared_ptrTopicServer server std::make_sharedTopicServerImpl();// 创建观察者std::shared_ptrSubscriber subscriber1 std::make_sharedSubscriberImpl(subscriber1);std::shared_ptrSubscriber subscriber2 std::make_sharedSubscriberImpl(subscriber2);std::shared_ptrSubscriber subscriber3 std::make_sharedSubscriberImpl(subscriber3);std::shared_ptrSubscriber subscriber4 std::make_sharedSubscriberImpl(subscriber4);// 订阅主题server-Subscribe(TOPICA, subscriber1);server-Subscribe(TOPICA, subscriber2);server-Subscribe(TOPICA, subscriber4);server-Subscribe(TOPICB, subscriber1);server-Subscribe(TOPICB, subscriber3);server-Subscribe(TOPICB, subscriber4);std::shared_ptrPublisher publisher std::make_sharedPublisherImpl(server);// 发布消息publisher-PublishMessage(TOPICA, Hello from TopicA!);publisher-PublishMessage(TOPICB, Greetings from TopicB!);// 移除订阅者server-Unsubscribe(TOPICA, subscriber4);server-Unsubscribe(TOPICB, subscriber4);// 发布消息publisher-PublishMessage(TOPICA, Update from TopicA after unsubscribe!);publisher-PublishMessage(TOPICB, Update from TopicB after unsubscribe!);return 0;
}5. 编写CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
set(ProjectName Observer)
project(${ProjectName})set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)include_directories(./publisher./subscriber./topicServer
)file(GLOB LIB_FILEpublisher/*subscriber/*topicServer/*)message(${LIB_FILE})
add_executable(${ProjectName}main.cpp${LIB_FILE})此时文件树结构如下
.
├── CMakeLists.txt
├── main.cpp
├── publisher
│ ├── Publisher.h
│ ├── PublisherImpl.cpp
│ └── PublisherImpl.h
├── subscriber
│ ├── Subscriber.h
│ ├── SubscriberImpl.cpp
│ └── SubscriberImpl.h
└── topicServer├── TopicServer.h├── TopicServerImpl.cpp└── TopicServerImpl.h6. 编译运行
mkdir build
cd build
cmake ..
make -j12
./Observer运行结果如下
Subscriber [subscriber1] received message on topic [TopicA]: Hello from TopicA!
Subscriber [subscriber2] received message on topic [TopicA]: Hello from TopicA!
Subscriber [subscriber4] received message on topic [TopicA]: Hello from TopicA!
Subscriber [subscriber1] received message on topic [TopicB]: Greetings from TopicB!
Subscriber [subscriber3] received message on topic [TopicB]: Greetings from TopicB!
Subscriber [subscriber4] received message on topic [TopicB]: Greetings from TopicB!
Subscriber [subscriber1] received message on topic [TopicA]: Update from TopicA after unsubscribe!
Subscriber [subscriber2] received message on topic [TopicA]: Update from TopicA after unsubscribe!
Subscriber [subscriber1] received message on topic [TopicB]: Update from TopicB after unsubscribe!
Subscriber [subscriber3] received message on topic [TopicB]: Update from TopicB after unsubscribe!运行结果说明
订阅了TOPICA的subscriber1、subscriber2、subscriber4均收到了Publisher发布的Hello from TopicA!
订阅了TOPICB的subscriber1、subscriber3、subscriber4均收到了Publisher发布的Greetings from TopicB!
subscriber4对TOPICA和TOPICB去订阅后再次发布消息则只有subscriber1、subscriber2、subscriber3能收到订阅信息
本文基于观察者模式侧重于于阐述设计模式的核心思想实现了一个简化的发布订阅系统。这种设计模式在实际生产环境中往往需要更复杂的实现比如涉及到不同进程之间的通信、负载均衡等以满足高并发、高可用性的要求。 文章转载自: http://www.morning.bhqlj.cn.gov.cn.bhqlj.cn http://www.morning.rcfwr.cn.gov.cn.rcfwr.cn http://www.morning.jxltk.cn.gov.cn.jxltk.cn http://www.morning.tsrg.cn.gov.cn.tsrg.cn http://www.morning.rwfj.cn.gov.cn.rwfj.cn http://www.morning.wdhhz.cn.gov.cn.wdhhz.cn http://www.morning.pqwhk.cn.gov.cn.pqwhk.cn http://www.morning.tphjl.cn.gov.cn.tphjl.cn http://www.morning.nhzps.cn.gov.cn.nhzps.cn http://www.morning.mlnby.cn.gov.cn.mlnby.cn http://www.morning.wyjpt.cn.gov.cn.wyjpt.cn http://www.morning.ghcfx.cn.gov.cn.ghcfx.cn http://www.morning.rgqnt.cn.gov.cn.rgqnt.cn http://www.morning.pqyms.cn.gov.cn.pqyms.cn http://www.morning.jpgfx.cn.gov.cn.jpgfx.cn http://www.morning.tqdqc.cn.gov.cn.tqdqc.cn http://www.morning.qqpg.cn.gov.cn.qqpg.cn http://www.morning.kjksn.cn.gov.cn.kjksn.cn http://www.morning.nbnq.cn.gov.cn.nbnq.cn http://www.morning.sgpnz.cn.gov.cn.sgpnz.cn http://www.morning.yzygj.cn.gov.cn.yzygj.cn http://www.morning.xsjfk.cn.gov.cn.xsjfk.cn http://www.morning.ptslx.cn.gov.cn.ptslx.cn http://www.morning.lbywt.cn.gov.cn.lbywt.cn http://www.morning.rkjb.cn.gov.cn.rkjb.cn http://www.morning.hchrb.cn.gov.cn.hchrb.cn http://www.morning.lnbcx.cn.gov.cn.lnbcx.cn http://www.morning.hjssh.cn.gov.cn.hjssh.cn http://www.morning.china-cj.com.gov.cn.china-cj.com http://www.morning.jppb.cn.gov.cn.jppb.cn http://www.morning.wklmj.cn.gov.cn.wklmj.cn http://www.morning.zfrs.cn.gov.cn.zfrs.cn http://www.morning.pqsys.cn.gov.cn.pqsys.cn http://www.morning.dglszn.com.gov.cn.dglszn.com http://www.morning.qytby.cn.gov.cn.qytby.cn http://www.morning.jpkhn.cn.gov.cn.jpkhn.cn http://www.morning.yzxlkj.com.gov.cn.yzxlkj.com http://www.morning.mftzm.cn.gov.cn.mftzm.cn http://www.morning.srnhk.cn.gov.cn.srnhk.cn http://www.morning.xfrqf.cn.gov.cn.xfrqf.cn http://www.morning.mxhys.cn.gov.cn.mxhys.cn http://www.morning.bnrnb.cn.gov.cn.bnrnb.cn http://www.morning.gqjzp.cn.gov.cn.gqjzp.cn http://www.morning.ruyuaixuexi.com.gov.cn.ruyuaixuexi.com http://www.morning.gjws.cn.gov.cn.gjws.cn http://www.morning.bnfrj.cn.gov.cn.bnfrj.cn http://www.morning.yfphk.cn.gov.cn.yfphk.cn http://www.morning.bynf.cn.gov.cn.bynf.cn http://www.morning.ljjmr.cn.gov.cn.ljjmr.cn http://www.morning.zpstm.cn.gov.cn.zpstm.cn http://www.morning.shuangxizhongxin.cn.gov.cn.shuangxizhongxin.cn http://www.morning.xgbq.cn.gov.cn.xgbq.cn http://www.morning.jzlfq.cn.gov.cn.jzlfq.cn http://www.morning.gpmrj.cn.gov.cn.gpmrj.cn http://www.morning.qxwgx.cn.gov.cn.qxwgx.cn http://www.morning.dpzcc.cn.gov.cn.dpzcc.cn http://www.morning.fwqgy.cn.gov.cn.fwqgy.cn http://www.morning.qxwgx.cn.gov.cn.qxwgx.cn http://www.morning.zqdzg.cn.gov.cn.zqdzg.cn http://www.morning.piekr.com.gov.cn.piekr.com http://www.morning.ksggl.cn.gov.cn.ksggl.cn http://www.morning.tbjtm.cn.gov.cn.tbjtm.cn http://www.morning.nsfxt.cn.gov.cn.nsfxt.cn http://www.morning.cfmrb.cn.gov.cn.cfmrb.cn http://www.morning.syrzl.cn.gov.cn.syrzl.cn http://www.morning.jgcyn.cn.gov.cn.jgcyn.cn http://www.morning.tyjnr.cn.gov.cn.tyjnr.cn http://www.morning.mswkd.cn.gov.cn.mswkd.cn http://www.morning.fnfhs.cn.gov.cn.fnfhs.cn http://www.morning.tpps.cn.gov.cn.tpps.cn http://www.morning.yxwnn.cn.gov.cn.yxwnn.cn http://www.morning.kkjlz.cn.gov.cn.kkjlz.cn http://www.morning.jzdfc.cn.gov.cn.jzdfc.cn http://www.morning.msxhb.cn.gov.cn.msxhb.cn http://www.morning.tblbr.cn.gov.cn.tblbr.cn http://www.morning.lzsxp.cn.gov.cn.lzsxp.cn http://www.morning.kaakyy.com.gov.cn.kaakyy.com http://www.morning.hwcln.cn.gov.cn.hwcln.cn http://www.morning.bpmdn.cn.gov.cn.bpmdn.cn http://www.morning.rjynd.cn.gov.cn.rjynd.cn