设计模式之工厂模式(二):实际案例

  设计模式之工厂模式(一)

        在阅读Qt网络部分源码时候,发现在某处运用了工厂模式,而且编程技巧也用的好,于是就想分享出来,供大家参考,理解的不对的地方请多多指点。

        以下是我整理出来的类图:

关键说明:

1.Q_GLOBAL_STATIC(QSocketEngineHandlerList, socketHandlers)

Qt实现单例模式:Q_GLOBAL_STATIC和Q_GLOBAL_STATIC_WITH_ARGS_qt 单例宏-CSDN博客

Q_GLOBAL_STATIC宏定义了一个全局变量,这个全局变量是定义在qabstractsocketengine.cpp中,它的定义如下:

class QSocketEngineHandlerList : public QList<QSocketEngineHandler*>
{
public:QMutex mutex;
};Q_GLOBAL_STATIC(QSocketEngineHandlerList, socketHandlers)

在cpp中定义,其它地方是访问不到这个全局变量,隐藏了实现,封装性比较好。

2.QAbstractSocketEngine和QHttpSocketEngine

在工厂模式中这个类就相当于是需要生产的对象,它是一个接口类,一般都是通过继承它来实现具体的功能。本例中QHttpSocketEngine就是实际的具有某个功能的类。

3.QSocketEngineHandler

这个类类似工厂模式中的工厂,它的定义如下:

class Q_AUTOTEST_EXPORT QSocketEngineHandler
{
protected:QSocketEngineHandler();virtual ~QSocketEngineHandler();virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType,const QNetworkProxy &, QObject *parent) = 0;virtual QAbstractSocketEngine *createSocketEngine(qintptr socketDescriptor, QObject *parent) = 0;private:friend class QAbstractSocketEngine;
};
QSocketEngineHandler::QSocketEngineHandler()
{if (!socketHandlers())return;QMutexLocker locker(&socketHandlers()->mutex);socketHandlers()->prepend(this);
}QSocketEngineHandler::~QSocketEngineHandler()
{if (!socketHandlers())return;QMutexLocker locker(&socketHandlers()->mutex);socketHandlers()->removeAll(this);
}

从上面的代码可以看出,在QSocketEngineHandler的构造函数和析构函数分别去注册和移除工厂,让继承QSocketEngineHandler的类也不用暴露socketHandlers,这个地方也是写的比较巧妙的地方。

4.QHttpSocketEngineHandler

具体的工厂类,负责生产QHttpSocketEngine,代码如下:

class Q_AUTOTEST_EXPORT QHttpSocketEngineHandler : public QSocketEngineHandler
{
public:virtual QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType,const QNetworkProxy &, QObject *parent) override;virtual QAbstractSocketEngine *createSocketEngine(qintptr socketDescripter, QObject *parent) override;
};
QAbstractSocketEngine *QHttpSocketEngineHandler::createSocketEngine(QAbstractSocket::SocketType socketType,const QNetworkProxy &proxy,QObject *parent)
{if (socketType != QAbstractSocket::TcpSocket)return 0;// proxy type must have been resolved by nowif (proxy.type() != QNetworkProxy::HttpProxy)return 0;// we only accept active socketsif (!qobject_cast<QAbstractSocket *>(parent))return 0;QHttpSocketEngine *engine = new QHttpSocketEngine(parent);engine->setProxy(proxy);return engine;
}QAbstractSocketEngine *QHttpSocketEngineHandler::createSocketEngine(qintptr, QObject *)
{return 0;
}

5.createSocketEngine()

在QAbstractSocketEngine类有两个静态函数,就是生产对象的入口:

class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject
{Q_OBJECT
public:static QAbstractSocketEngine *createSocketEngine(QAbstractSocket::SocketType socketType, const QNetworkProxy &, QObject *parent);static QAbstractSocketEngine *createSocketEngine(qintptr socketDescriptor, QObject *parent);QAbstractSocketEngine(QObject *parent = 0);...
};
QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(QAbstractSocket::SocketType socketType, const QNetworkProxy &proxy, QObject *parent)
{
#ifndef QT_NO_NETWORKPROXY// proxy type must have been resolved by nowif (proxy.type() == QNetworkProxy::DefaultProxy)return 0;
#endifQMutexLocker locker(&socketHandlers()->mutex);for (int i = 0; i < socketHandlers()->size(); i++) {if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketType, proxy, parent))return ret;}#ifndef QT_NO_NETWORKPROXY// only NoProxy can have reached hereif (proxy.type() != QNetworkProxy::NoProxy)return 0;
#endifreturn new QNativeSocketEngine(parent);
}QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(qintptr socketDescripter, QObject *parent)
{QMutexLocker locker(&socketHandlers()->mutex);for (int i = 0; i < socketHandlers()->size(); i++) {if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketDescripter, parent))return ret;}return new QNativeSocketEngine(parent);
}

在函数createSocketEngine中依次循环调用socketHandlers()来创建QAbstractSocketEngine,这里的类型过滤是在具体的创建函数中,比如QHttpSocketEngineHandler::createSocketEngine。

6.总结

        虽然工厂模式并不复杂,但是要在实际项目中灵活运用,也不是一件容易的事,希望我的分享会对你更好的理解工厂模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/80542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MultiTTS 1.7.6 | 最强离线语音引擎,提供多音色无障碍朗读功能,附带语音包

MultiTTS是一款免费且支持离线使用的文本转语音&#xff08;TTS&#xff09;工具&#xff0c;旨在为用户提供丰富的语音包选项&#xff0c;实现多音色无障碍朗读功能。这款应用程序特别适合用于阅读软件中的离线听书体验&#xff0c;提供了多样化的语音选择&#xff0c;使得听书…

歌曲《忘尘谷》基于C语言的歌曲调性检测技术解析

引言 在音乐分析与数字信号处理领域&#xff0c;自动检测歌曲调性是一项基础且关键的任务。本文以C语言为核心&#xff0c;结合音频处理库&#xff08;libsndfile&#xff09;和快速傅里叶变换库&#xff08;FFTW&#xff09;&#xff0c;探讨如何实现调性检测&#xff0c;并通…

大某麦演唱会门票如何自动抢

引言 仅供学习研究&#xff0c;欢迎交流 抢票难&#xff0c;难于上青天&#xff01;无论是演唱会、话剧还是体育赛事&#xff0c;大麦网的票总是秒光。大麦网是国内知名的票务平台&#xff0c;热门演出票往往一票难求。手动抢票不仅耗时&#xff0c;还容易错过机会。作为一名…

1.3.3 tinyalsa详细介绍

一、TinyALSA 的背景与设计目标 1. 诞生背景 Android 音频需求的演变&#xff1a;早期 Android 系统使用标准 ALSA&#xff08;Advanced Linux Sound Architecture&#xff09;的用户空间库 alsa-lib&#xff0c;但因其复杂性&#xff08;代码庞大、依赖较多&#xff09;和资…

超越合并速度(merge speed):AI如何重塑开发者协作

李升伟 编译 AI 关于现代开发的讨论通常围绕着单一指标&#xff1a;合并速度&#xff08;merge speed&#xff09;。但在这一表面测量之下&#xff0c;隐藏着开发团队工作方式的一种更深刻的变革。让我们探讨开发者协作的微妙演变方式以及为什么传统生产力指标只讲述了一部分故…

如何找正常运行虚拟机

1.新建虚拟机。Linux centos7&#xff0c;给虚拟机改个名字不要放在c盘 2.安装操作系统。cd/dvd->2009.iso 启动虚拟机

深度学习:系统性学习策略(二)

深度学习的系统性学习策略 基于《认知觉醒》与《认知驱动》的核心方法论,结合深度学习的研究实践,从认知与技能双重维度总结以下系统性学习策略: 一、认知觉醒:构建深度学习的思维操作系统 三重脑区协同法则 遵循**本能脑(舒适区)-情绪脑(拉伸区)-理智脑(困难区)**的…

如何使用CSS解决一行有三个元素,前两个元素靠左排列,第三个元素靠右排列的问题

如图所示&#xff0c;我要把左边的场馆和区域信息靠左排列&#xff0c;价格信息靠右排列。如何使用CSS实现这种效果&#xff1f; 在这里&#xff0c;我使用了flexbox弹性布局&#xff0c;以下是我的实现代码 .name-info {display: flex;gap: 2px;justify-content: space-betwee…

USB传输模式

USB有四种传输模式: 控制传输, 中断传输, 同步传输, 批量传输 1. 中断传输 中断传输一般用于小批量, 非连续的传输. 对实时性要求较高. 常见的使用此传输模式的设备有: 鼠标, 键盘等. 要注意的是, 这里的 “中断” 和我们常见的中断概念有差异. Linux中的中断是设备主动发起的…

【Python 变量类型】

Python 是一种动态类型语言&#xff0c;变量类型在运行时自动确定&#xff0c;无需显式声明。以下是 Python 中核心变量类型的分类与用法详解&#xff1a; 一、基本数据类型 1. 数值类型 整数 (int) 支持正负数、零和二进制/八进制/十六进制表示&#xff1a; a 42 b 0o52 #…

Python基础:类的深拷贝与浅拷贝-->with语句的使用及三个库:matplotlib基本画图-->pandas之Series创建

一.类的深拷贝与浅拷贝 class CPU():pass class Disk():passclass Computer():#计算机由CPU和硬盘组成def __init__(self):self.cpu CPU()self.disk Disk()cpu CPU()#创建一个CPU对象 disk Disk()#创建一个硬盘对象#创建一个计算机对象 com Computer(cpu,disk) #变量&…

【SSM-SpringMVC(二)】Spring接入Web环境!本篇开始研究SpringMVC的使用!SpringMVC数据响应和获取请求数据

SpringMVC的数据响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 页面跳转&#xff1a; 返回字符串方式 直接返回字符串&#xff1a;此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转 RequestMapping("/con&…

阅文集团C++面试题及参考答案

目录 能否不使用锁保证多线程安全? 面向对象的三个特性是什么?请分别解释。 构造函数和析构函数能否被继承? C++ 中函数重载是如何实现的? C 语言中是否支持函数重载? 什么是左值和右值?请举例说明。 C++ 中子类的构造和析构顺序是怎样的? C++ 中虚函数表的变化过…

【亲测有效】如何清空但不删除GitHub仓库中的所有文件(main分支)

如何清空但不删除GitHub仓库中的所有文件&#xff08;main分支&#xff09; 在项目开发过程中&#xff0c;有时我们需要清空GitHub仓库中的所有文件&#xff0c;同时保留仓库本身。这种情况常见于项目重构、代码重写或者需要重新开始一个项目时。本文将介绍一种有效的方法来清…

前端EXCEL插件,智表ZCELL产品V3.0 版本发布,底层采用canvas全部重构,功能大幅扩展,性能极致提升,满足千万级单元格加载

本次更新是底层全部重构&#xff0c;按照现代浏览器要求&#xff0c;采用canvas方式进行了重构&#xff0c;预留了将来扩展空间&#xff0c;特别是在大数据量性能提升方面有了较大提升&#xff0c;可以满足千万级单元格加载&#xff0c;欢迎大家体验使用。 体验地址&#xff1…

3DGS-to-PC:3DGS模型一键丝滑转 点云 or Mesh 【Ubuntu 20.04】【2025最新版!!】

一、引言 3D高斯泼溅(3DGS)是一种新兴的三维场景表示方法&#xff0c;可以生成高质量的场景重建结果。然而&#xff0c;要查看这些重建场景&#xff0c;需要特殊的高斯渲染器。大多数3D处理软件并不兼容3D高斯分布模型&#xff0c;但它们通常都兼容点云文件。 3DGS-to-PC项目提…

OpenHarmony 以太网卡热插拔事件接口无效

目录 1.背景 2.解决方案 1.背景 在OpenHarmony中调用以太网热插拔时间,发现热插拔没有任何回调,如下接口 import { ethernet } from @kit.NetworkKit;ethernet.on(interfaceStateChange, (data: object) => {console.log(on interfaceSharingStateChange: + JSON.…

C++ 跨平台开发挑战与深度解决方案:从架构设计到实战优化

C 凭借其高性能与底层控制能力&#xff0c;在游戏引擎、嵌入式系统、工业软件等领域占据核心地位。然而&#xff0c;跨平台开发过程中需应对硬件架构多样性、操作系统差异性、编译工具链碎片化等复杂问题。本文将从底层架构到上层应用&#xff0c;系统性剖析 C 跨平台开发的核心…

什么是 ANR 如何避免它

一、什么是 ANR&#xff1f; ANR&#xff08;Application Not Responding&#xff09; 是 Android 系统在应用程序主线程&#xff08;UI 线程&#xff09;被阻塞超过一定时间后触发的错误机制。此时系统会弹出一个对话框提示用户“应用无响应”&#xff0c;用户可以选择等待或强…

数据结构(六)——树和二叉树

一、树和二叉树的定义与存储 1.树的定义 树是一种非线性的数据结构&#xff0c;它是由n个有限结点组成有层次关系的集合 树具有以下特点&#xff1a; &#xff08;1&#xff09;每个结点具有0个或多个子结点 &#xff08;2&#xff09;每个子结点只有一个父结点 &#xff…