設計模式之工廠模式(二):實際案例

??設計模式之工廠模式(一)

????????在閱讀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.pswp.cn/pingmian/80542.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80542.shtml
英文地址,請注明出處:http://en.pswp.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…