C++屌屌的屌屌的調和觀(guān)察者模式ヽ(′ー`)ノ(同步回調和異步回調) 一ヽ(′▽?zhuān)?ノ、概述 說(shuō)起觀(guān)察者模式,觀(guān)察也是式同比較簡(jiǎn)單的一種模式了,稍微工作有1年經(jīng)驗的異步同ヽ(′?`)ノ學(xué),寫(xiě)起來(lái)都是回調666̷(′;ω;`)0; 想看觀(guān)察者模式的說(shuō)明ヽ(′ー`)ノ可以直接上菜鳥(niǎo)教程|觀(guān)察者模式(shi)這個(gè)地址去看。 本篇文章其實(shí)就是屌屌的調和一個(gè)簡(jiǎn)單的觀(guān)察者模式,只是觀(guān)察使用了模板的方式,把我們的式同回調接口進(jìn)行了參數化,這樣有什么?好處呢?異步 好處當然是大大的有了。平時(shí)我們在不同業(yè)務(wù)邏輯之間寫(xiě)觀(guān)察者(zhe)模式呢,回調都得寫(xiě)好多個(gè),屌屌的調和大家??有沒(méi)有發(fā)現(xian),觀(guān)察所有???的式同被觀(guān)察者Subject其實(shí)很多操作都是(′?`*)一樣的。 本篇我們帶來(lái)兩種(zhong)觀(guān)察者模式:同步觀(guān)察者和異步觀(guān)察者 1、異步同步觀(guān)察者 顧名思義,回調同步觀(guān)察者其實(shí)就是不管是誰(shuí),觸發(fā)了Subject的Update操作,該操作都是同步進(jìn)行的,他會(huì )調用所有的觀(guān)察者(Observer)的OnUpdate接口,來(lái)通知Observer處理改變操作。 如效果展示圖中的??第一個(gè)單次拉取頁(yè)簽,當我們點(diǎn)擊拉取按鈕時(shí),就相當于觸發(fā)了一次Subject對象的Update操作 2、異步觀(guān)察者 異步觀(guān)察者模式上和同步觀(guān)察者基本一樣,只是在事件處理上有稍微不同 如效果圖所示,定時(shí)拉取觀(guān)察者模式,Subject啟動(dòng)了一個(gè)后臺線(xiàn)程,3秒鐘拉取一次數據,并回調到界面
如下圖所示,是一個(gè)簡(jiǎn)單的觀(guān)察者模式事例。
單次拉?。貉菔玖?′?`)同步觀(guān)察者模式
定時(shí)拉?。貉菔玖水惒接^(guān)察者模式
工程結構如圖所示,這里只把頭文件的??目錄展示出來(lái)了。
Header Files目錄下有2個(gè)虛擬文件(???)夾,分別就是對單次拉取和定時(shí)拉取??功能的實(shí)踐
下面我們就來(lái)正式開(kāi)??始講解這個(gè)屌屌的觀(guān)(guan)察者模式
三、(′?_?`)同步觀(guān)察者
1、首先就是定義一堆接口和回調參數
struct DataItem{ std::string strID; std::string strName; };typedef IUpdate1<DataItem&??gt; ISignalObserver;??//單次回調stヽ(′ー`)ノruct ISignal : public SubjectBase<ISignalObserver>{ virtual voi(′?ω?`)d RequestData() = 0;};2、業(yè)務(wù)觀(guān)察者
這里我定義了一個(gè)SignalResponse業(yè)務(wù)觀(guān)察者,也就是我們在開(kāi)發(fā)工程中的實(shí)際功能類(lèi)。
class SignalResponse : public ISignal{ public: SignalResponse(); ~SignalResponse();public: virtual void RequestData() override;private: };通過(guò)一個(gè)門(mén)面接口獲取觀(guān)察者指針
調用ISignal的Attach接口,就可以把自己添加到觀(guān)察(′?`*)者列表。調用ISignal的RequestData接口,就可以拉取數據。調用ISignal的Detach接口,就可以把自己從觀(guān)察者列表中(′▽?zhuān)?移除。ISignal * GetSignalCommon();4、UI界面
接下來(lái)就是寫(xiě)一個(gè)UI界面啦,當我們通過(guò)上一步調用拉取數據接口后,我們的UI上相應的OnUpdate接口就會(huì )被回調
class SignalWidg(?_?;)et : public?? QWidget, publi(′▽?zhuān)?c ISignalObserver{ Q_OBJEC(′;д;`)Tpublic: SignalWidget(QWidget * parent = 0); ~Si??gnalWidget();protected: virtual void OnUp??date(const DataItem &) over??ride;(╯‵□′)╯private slots: void on_pushButton_clicked();private: Ui::SignalWidget *ui;};通過(guò)以上四步,就可以很方便的實(shí)現一個(gè)現在業(yè)務(wù)中的觀(guān)?察者,是不是很簡(jiǎn)單呢,編寫(xiě)過(guò)程中,需要完成這幾個(gè)地方
需(???)要定義我們回調函數的參數結構需要實(shí)例化一個(gè)被觀(guān)察者ヾ(′▽?zhuān)??接口類(lèi)實(shí)例化一個(gè)業(yè)務(wù)觀(guān)察者做一個(gè)UI界面,并集成第ヽ(′▽?zhuān)?/二步實(shí)例化的被觀(guān)察者的模板參數(接口類(lèi))注意看這里的ISignalObserver,是不是很眼熟,其實(shí)他就是我們的模板被觀(guān)察者SubjectBase的模板參數。
講到這里,大家是不是都很關(guān)心這個(gè)模板觀(guān)察者到底是何方神圣,居然這么叼。那么接下來(lái)就是模板SubjectBase出場(chǎng)啦。。??。
四、異步觀(guān)察者
異步觀(guān)察者(╯°□°)╯的實(shí)現和同步觀(guān)察者的結構基本一樣,都是使用(yong)同樣的套路,唯一有區別的地方就是,異步觀(guān)(????)察者所有的邏輯處理操作都是在工作線(xiàn)程中的。
由于IT??imerSubject和SubjectBase很??多接口都是一樣的,因此我這里就只把差異的部分貼出來(lái)(°o°)。
1、線(xiàn)程
ITimerSubject對象在構造時(shí),就啟動(dòng)了一( ?ω?)個(gè)線(xiàn)程,然后在(zai)線(xiàn)程中定時(shí)執行TimerNotify函數
ITimerSubject(){ m_thread = std::thread(std::bind(&ITimerSubject::TimerNotify, this));}vir(′▽?zhuān)?tual ~ITimer(╯°□°)╯︵ ┻━┻Subject(){ m_thread.join();}再(?????)來(lái)看下定時(shí)處理任務(wù)這個(gè)函數,這個(gè)函數本身是用boost的庫實(shí)現(xian)我的,我改成C++11的模式的,新城退出這塊有些問(wèn)題,我沒(méi)有處理,這個(gè)也不是本篇文章的核心要講解的東西。
怎么優(yōu)雅的退出std::thread,這個(gè)從網(wǎng)上查下??資料吧,我能想到的也就是加一個(gè)標識,然后子??線(xiàn)程??去判斷。如果大家有更好??的辦法的話(huà)可以(yi)私信我,或者在底部留言。
void TimerNotify(){ for (;;) { //std::this_thread::interruption_point(); bool bNotify = false; { std::lock_gu??ard<std::mutex> lg(m_mutex); bNotify = m_sleepin??g_observers.size() < m_observers.size() ? true : false; } if (bNotify) { OnTimerNotify(); } //std::this_thread::interruption_point(); std::(′?ω?`)chrono::milliseconds timespan(GetTimerInterval() * 1000); // or whatever std::this_thread::sleep_for(timespan); }}2、定義一??堆接口和回調參數
struct TimerDataItem??{ std::string strID; std::string strName;};typedef IUpdate1<TimerDataItem> ITimerObserver;//??定時(shí)回調struct ITimer : public ITimerSubject<ITimerObserver, std::string,?? TimerDataItem>{ };3、業(yè)務(wù)觀(guān)察者
這里我定義了一個(gè)TimerResponse??業(yè)務(wù)觀(guān)察者,也就是我們在開(kāi)發(fā)工程中的實(shí)際功能類(lèi)。
class TimerResp??onse : public ITimer{ public: TimerR(╥_╥)esponse(); ~TimerRes??ponse();protected: virtual void OnNotify() override;private: };TimerResponse::OnNotify()這個(gè)接口的實(shí)現就像這樣,這里需要注意的一點(diǎn)是,這個(gè)函數的執行位于工作線(xiàn)程中,也就意味著(zhù)UI界面的回┐(′ー`)┌調函數也在工作線(xiàn)程中,操作UI界面時(shí),一定??需要拋事件到UI??線(xiàn)程中。
void TimerResponse::OnNotify(){ static int id = 0; static std::string name = "miki"; id += 1; TimerDataIt??em item;?? std::stringstream ss; ss << "timer" &l(′▽?zhuān)?t;??< id; item.strID = ss.str(); item.strName = name; UpdateImpl??(item);}OnNotify會(huì )定時(shí)被調用,然后去(qu)更(′ω`)新UI上的內容。
4ヽ(′ー`)ノ、獲取觀(guān)察者指針
定時(shí)回調功能測試界面
on_pushButton_clicked槽函數只是(′?`)為了把當前線(xiàn)程喚醒,并定時(shí)回調OnUpdate屬于定時(shí)回調接口class TimerWidget : public QWidget, public ITimerObse??rver{ Q_OBJECTpublic: TimerWidget(QW??idget *parent = 0); ~Tim(╯‵□′)╯erWidget();protected: virtual void OnU??pdate(const TimerDat(′_`)aItem &) override;private slots: void on_pus(′-ι_-`)hBu??tton_clicked();signals: void RerfushData(Time??rDataItem);private: Ui::TimerWidget *ui;};上邊也強調過(guò)了,On(′?`)Update的執行是在工作線(xiàn)程中的,因此實(shí)現的時(shí)候,如果涉及到訪(fǎng)問(wèn)UI界面,一定要注意切換線(xiàn)程
void TimerWidget::(′;д;`)OnUpdate(const TimerDataItem & item){ //注意這里的定時(shí)回調都在工作線(xiàn)程中 需要切換到主線(xiàn)程 emit RerfushData(item);}以上講解就是我們觀(guān)察者的實(shí)現了,如果有疑問(wèn)歡迎提出
根據搜索結果,鶴壁地區專(zhuān)業(yè)網(wǎng)站建設公司推薦如下,綜合實(shí)力、服務(wù)范圍及行業(yè)案例進(jìn)行篩選: 一、綜合實(shí)力型推薦明企科技 16年企業(yè)及個(gè)人網(wǎng)站建設經(jīng)驗,覆蓋電商、教育、機械、農業(yè)等多領(lǐng)域提供電商信息化解決方 ..
圖片識別是計算機視覺(jué)領(lǐng)域的一個(gè)重要研究方向,它的目標是讓計算機能夠像人類(lèi)一樣理解和處理圖像信息,在C語(yǔ)言中實(shí)現圖片識別,我們可以采用一些開(kāi)源的計算機視覺(jué)庫,如OpenCV,open='open'CVOpen Sou ..
在C語(yǔ)言中,"不封裝"通常指的是直接使用全局變量、函數和其他實(shí)體,而不是將它們封裝在結構體、對象或模塊中,這種做法可能導致代碼的可維護性降低,因為全局狀態(tài)使得程序的行為更難以預測和 ..
越秀網(wǎng)站開(kāi)發(fā)的定制價(jià)格受多種因素影響,包括網(wǎng)站的功能需求、設計復雜度、開(kāi)發(fā)難度以及后期維護服務(wù)。以下是一些具體的報價(jià)范圍:普通企業(yè)網(wǎng)站常規布局、功能和欄目的網(wǎng)站建設報價(jià)約為1,2千元人民幣。功能模塊不 ..





