C++中小项目软件开发架构源码

描述

主要用于单线程的类之间的交互调用,实现了类似QT信号槽的调用,同时集成了观察者模式。创作不易,转载使用请标注来源,感谢。https://blog.csdn.net/weixin_42210846?type=blog

特性

  1. 仅需包含一个头文件Communicator.h,需要通信的类继承Communicator即可。
  2. 消息通过枚举类型定义,支持任意枚举消息,添加枚举无需改动代码。枚举名称区分消息类型,枚举值区分具体消息
  3. 使用便捷,只需注册消息和消息处理函数
  4. 提供发送消息时,附带any传递任意额外信息
  5. 哈希方式存储消息和处理函数的映射,性能高,不存在多态等机制的开销
  6. 提供观察者模式供消息回传

对比QT信号槽

1.不支持多线程
2.使用同QT一样便捷,只需注册消息和消息回调函数。且如果使用QT的信号槽进行通信,不同的消息的类型则需要定义多个connect连接函数,如ELoginMsg、ERunMsg,多一种消息就要多一个connect
3.性能优于QT信号槽,通讯者收到消息后直接调用消息处理函数,QT信号槽的性能开销是普通函数调用的10倍
4.纯C++实现,不需要任何插件支持,如QT需要moc机制支持
5.使用到较多C++特性,需要学习成本

源码

Communicator.h

#pragma once
#include <any>
#include <functional>
#include <memory>
#include <unordered_map>

class Communicator : public std::enable_shared_from_this<Communicator> {
	using MsgID = size_t;
	using MsgCallback = std::any;
	using CallbackFmt1 = std::function<void()>;
	using CallbackFmt2 = std::function<void(const std::any&)>;
	using CommunicatorPtr = std::shared_ptr<Communicator>;
	using CommunicatorPtrVec = std::vector<CommunicatorPtr>;
public:
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	void RegisterMsgHandle(T msg, CallbackFmt1 func) {
		m_msgHandler.insert({ Hash(msg), func });
	}
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	void RegisterMsgHandle(T msg, CallbackFmt2 func) {
		m_msgHandler.insert({ Hash(msg), func });
	}
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	void Handle(T msg, const std::any& info = std::any{}) {
		size_t hash = Hash(msg);
		if (bool findHandler = m_msgHandler.find(hash) != m_msgHandler.end()) {
			m_msgHandler[hash].type() == typeid(CallbackFmt1) ? std::any_cast<CallbackFmt1>(m_msgHandler[hash])()
				: std::any_cast<CallbackFmt2>(m_msgHandler[hash])(info);
		}
	}
	// sigslot
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	void Connect(T msg, CommunicatorPtr receiver) {
		if (receiver != nullptr) {
			m_receivers[Hash(msg)].push_back(receiver);
		}
	}
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	void Emit(T msg, const std::any& info = std::any{}) {
		if (bool findReceiver = m_receivers.find(Hash(msg)) != m_receivers.end()) {
			for (const auto& receiver : m_receivers[Hash(msg)]) {
				if (receiver != nullptr) {
					receiver->Handle(msg, info);
				}
			}
		}
	}
	// observer
	void Add(CommunicatorPtr observer) {
		if (bool notAdd = std::ranges::find(m_observers, observer) == m_observers.end()) {
			m_observers.push_back(observer);
		}
	}
	void Remove(CommunicatorPtr observer) {
		if (auto findit = std::ranges::find(m_observers, observer); findit != m_observers.end()) {
			m_observers.erase(findit);
		}
	}
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	void Notify(T msg, const std::any& info = std::any{}) {
		for (const auto& observer : m_observers) {
			if (observer != nullptr) {
				observer->Handle(msg, info);
			}
		}
	}
private:
	template<typename T, typename = std::enable_if_t<std::is_enum_v<T>, void>>
	MsgID Hash(T msg) const {
		return std::hash<size_t>()(static_cast<size_t>(msg)) ^ std::hash <std::string>()(typeid(T).name());
	}
private:
	std::unordered_map<MsgID, MsgCallback> m_msgHandler;
	CommunicatorPtrVec m_observers;
	std::unordered_map<MsgID, CommunicatorPtrVec> m_receivers;
};

main.cpp

#include <iostream>
#include "Communicator.h"
using namespace std;

enum class EMsgA {
	MSG_A_1,
	MSG_A_2,
};

enum class EMsgB {
	MSG_B_1,
	MSG_B_2,
};

struct humaninfo {
	std::string name;
	std::string sex;
	std::string id;
};

class View : public Communicator {
public:
	View() {
		RegisterMsgHandle(EMsgA::MSG_A_1, [this] { ProcessMSGA1(); });
		RegisterMsgHandle(EMsgB::MSG_B_2, [this](const std::any& info) {ProcessMSGB2(info); });
	}
	void Call() {
		Emit(EMsgA::MSG_A_1);
		Emit(EMsgB::MSG_B_2, humaninfo{ "flower", "man", "19980323" });
	}
private:
	void ProcessMSGA1() {
		cout << "exec ProcessMSGA1 finished" << endl;
	}
	void ProcessMSGB2(const std::any& info) {
		cout << "exec ProcessMSGB2 finished" << endl;
		auto hInfo = std::any_cast<humaninfo>(info);
		auto name = hInfo.name;
		auto sex = hInfo.sex;
		auto id = hInfo.id;
		cout << "name = " << name << ", sex = " << sex << ", id = " << id << endl;
	}
};

struct Business :Communicator {
	Business() {
		RegisterMsgHandle(EMsgA::MSG_A_1, [this] {ProcessMSGA1(); });
		RegisterMsgHandle(EMsgB::MSG_B_2, [this](const std::any& info) {ProcessMSGB2(info); });
	}
	void ProcessMSGA1() {
		cout << "exec ProcessMSGA1" << endl;
		Notify(EMsgA::MSG_A_1);
	}
	void ProcessMSGB2(const std::any& info) {
		auto hInfo = std::any_cast<humaninfo>(info);
		auto name = hInfo.name;
		auto sex = hInfo.sex;
		auto id = hInfo.id;
		cout << "exec ProcessMSGB2, name = " << name << ", sex = " << sex << ", id = " << id << endl;
		Notify(EMsgB::MSG_B_2, info);
	}
};

int main()
{
	std::shared_ptr<Communicator> business = std::make_shared<Business>();
	std::shared_ptr<View> view = std::make_shared<View>();

	business->Add(view);
	view->Connect(EMsgA::MSG_A_1, business);
	view->Emit(EMsgA::MSG_A_1);
	//view->Call();
	getchar();
	return 0;
}
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flower980323

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值