C++設(shè)計(jì)模式基礎(chǔ)教程_第1頁(yè)
C++設(shè)計(jì)模式基礎(chǔ)教程_第2頁(yè)
C++設(shè)計(jì)模式基礎(chǔ)教程_第3頁(yè)
C++設(shè)計(jì)模式基礎(chǔ)教程_第4頁(yè)
C++設(shè)計(jì)模式基礎(chǔ)教程_第5頁(yè)
已閱讀5頁(yè),還剩200頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

C/C++與設(shè)計(jì)模式根底課程

設(shè)計(jì)模式根底

1設(shè)計(jì)模式編程根底

1.1設(shè)計(jì)模式前言

模式

在一定環(huán)境中解決某一問(wèn)題的方案,包括三個(gè)根本元素-問(wèn)題,解決方案和環(huán)境。

大白話:在一定環(huán)境下,用固定套路解決問(wèn)題。

設(shè)計(jì)模式(Designpattern)

是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)

模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。毫無(wú)疑問(wèn),設(shè)計(jì)模

式于己于他人于系統(tǒng)都是多贏的;設(shè)計(jì)模式使代碼編制真正工程化;

設(shè)計(jì)模式是軟件工程的基石脈絡(luò),如同大廈的結(jié)構(gòu)一樣。

學(xué)習(xí)設(shè)計(jì)模式的意義

提高職業(yè)素養(yǎng),關(guān)注學(xué)員在行業(yè)內(nèi)的長(zhǎng)期開展。

“我眼中的設(shè)計(jì)模式"

把簡(jiǎn)單的問(wèn)題復(fù)雜化(標(biāo)準(zhǔn)化),把環(huán)境中的各個(gè)局部進(jìn)行抽象、歸納、解耦合。

不是多神秘的東西,我們初學(xué)者也能學(xué)的會(huì)。要有信心。

學(xué)習(xí)設(shè)計(jì)模式的方法

對(duì)初學(xué)者:

積累案例,大于背類圖。

初級(jí)開發(fā)人員:

多思考、多梳理,歸納總結(jié);

尊重事物的認(rèn)知規(guī)律,注意事物臨界點(diǎn)的突破。不可急躁。

中級(jí)開發(fā)人員

適宜的開發(fā)環(huán)境,尋找適宜的設(shè)計(jì)模式,解決問(wèn)題。

多應(yīng)用

對(duì)經(jīng)典組合設(shè)計(jì)模式的大量、自由的運(yùn)用。要不斷的追求。

設(shè)計(jì)模式的分類

GangofFour的**DesignPatterns:ElementsofResualbelSoftware"書將設(shè)計(jì)模式歸納為

三大類型,共23種。

創(chuàng)立型模式:通常和對(duì)象的創(chuàng)立有關(guān),涉及到對(duì)象實(shí)例化的方式。(共5種模式)

結(jié)構(gòu)型模式:描述的是如何組合類和對(duì)象以獲得更大的結(jié)構(gòu)。(共7種模式)

行為型模式:用來(lái)對(duì)類或?qū)ο笤鯓咏换ズ驮鯓臃峙渎氊?zé)進(jìn)行描述。(共11種模式)

創(chuàng)立型模式用來(lái)處理對(duì)象的創(chuàng)立過(guò)程,主要包含以下5種設(shè)計(jì)模式:

1,工廠方法模式(FactoryMethodPattern)的用意是定義一個(gè)創(chuàng)立產(chǎn)品對(duì)象的工廠接口,

將實(shí)際創(chuàng)立工作推遲到子類中。

2,抽象工廠模式(AbstractFactoryPattern)的意圖是提供-一個(gè)創(chuàng)立一系列相關(guān)或者相互依

賴的接口,而無(wú)需指定它們具體的類。

3,建造者模式(BuilderPattern)的意圖是將一個(gè)復(fù)雜的構(gòu)建與其表示相別離,使得同樣的

構(gòu)建過(guò)程可以創(chuàng)立不同的表示。

4,原型模式(PrototypePattern)是用原型實(shí)例指定創(chuàng)立對(duì)象的種類,并且通過(guò)拷貝這些原

型創(chuàng)立新的對(duì)象。

5,單例模式(SingletonPattern)是保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪

問(wèn)點(diǎn)。

結(jié)構(gòu)型模式用來(lái)處理類或者對(duì)象的組合,主要包含以下7種設(shè)計(jì)模式:

6,代理模式(ProxyPattern)就是為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。

7,裝飾者模式(DecoratorPattern)動(dòng)態(tài)的給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)

說(shuō),此模式比生成子類更為靈活。

8,適配器模式(AdapterPattern)是將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。使得

原本由于接口不兼容而不能一起工作的那些類可以一起工作。

9,橋接模式(BridgePattern)是將抽象局部與實(shí)際局部別離,使它們都可以獨(dú)立的變化。

10,組合模式(CompositePattern)是將對(duì)象組合成樹形結(jié)構(gòu)以表示"局部-整體”的層次結(jié)

構(gòu)。使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。

11,外觀模式(FacadePattern)是為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,此模式定義

了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。

12,享元模式(FlyweightPattern)是以共享的方式高效的支持大量的細(xì)粒度的對(duì)象。

行為型模式用來(lái)對(duì)類或?qū)ο笤鯓咏换ズ驮鯓臃峙渎氊?zé)進(jìn)行描述,主要包含以下11種設(shè)計(jì)模

式:

13,模板方法模式(TemplateMethodPattern)使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重

定義該算法的某些特定步驟。

14,命令模式(CommandPattern)是將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)

求對(duì)客戶端進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可撤銷的操作。

15,責(zé)任鏈模式(ChainofResponsibilityPattern),在該模式里,很多對(duì)象由每—個(gè)對(duì)象對(duì)其

下家的引用而連接起來(lái)形成一條鏈。請(qǐng)求在這個(gè)鏈上傳遞,直到鏈上的某一個(gè)對(duì)象決定處理

此請(qǐng)求,這使得系統(tǒng)可以在不影響客戶端的情況下動(dòng)態(tài)地重新組織鏈和分配責(zé)任。

16,策略模式(StrategyPattern)就是準(zhǔn)備一組算法,并將每一個(gè)算法封裝起來(lái),使得它們

可以互換。

17,中介者模式(MediatorPattern)就是定義一個(gè)中介對(duì)象來(lái)封裝系列對(duì)象之間的交互。終

結(jié)者使各個(gè)對(duì)象不需要顯示的相互調(diào)用,從而使其耦合性松散,而且可以獨(dú)立的改變他們

之間的交互。

18,觀察者模式(ObserverPattern)定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀

態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。

19,備忘錄模式(MementoPattern)是在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),

并在該對(duì)象之外保存這個(gè)狀態(tài)。

20,訪問(wèn)者模式(VisitorPattern)就是表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作,它使

你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。

21,狀態(tài)模式(StatePattern)就是對(duì)象的行為,依賴于它所處的狀態(tài)。

22,解釋器模式(InterpreterPattern)就是描述了如何為簡(jiǎn)單的語(yǔ)言定義一個(gè)語(yǔ)法,如何在

該語(yǔ)言中表示一個(gè)句子,以及如何解釋這些句子。

23,迭代器模式(IteratorPattern)是提供了一種方法順序來(lái)訪問(wèn)一個(gè)聚合對(duì)象中的各個(gè)元

素,而又不需要暴露該對(duì)象的內(nèi)部表示。

1.2設(shè)計(jì)模式根本原那么

最終目的:高內(nèi)聚,低耦合

1)開放封閉原那么(OCP,OpenForExtension,ClosedForModificationPrinciple)

類的改動(dòng)是通過(guò)增加代碼進(jìn)行的,而不是修改源代碼。

2)單一職責(zé)原那么(SRP,SingleResponsibilityPrinciple)

類的職責(zé)要單一,對(duì)外只提供一種功能,而引起類變化的原因都應(yīng)該只有一個(gè)。

3)依賴倒置原那么(DIP,DependenceInversionPrinciple)

依賴于抽象(接口),不要依賴具體的實(shí)現(xiàn)(類),也就是針對(duì)接口編程。

4)接口隔離原那么(ISP,InterfaceSegegationPrinciple)

不應(yīng)該強(qiáng)迫客戶的程序依賴他們不需要的接口方法。一個(gè)接口應(yīng)該只提供一種對(duì)外功能,

不應(yīng)該把所有操作都封裝到一個(gè)接口中去。

5)里氏替換原那么(LSP,LiskovSubstitutionPrinciple)

任何抽象類出現(xiàn)的地方都可以用他的實(shí)現(xiàn)類進(jìn)行替換。實(shí)際就是虛擬機(jī)制,語(yǔ)言級(jí)別實(shí)

現(xiàn)面向?qū)ο蠊δ堋?/p>

6)優(yōu)先使用組合而不是繼承原那么(CARP,Composite/AggregateReusePrinciple)

如果使用繼承,會(huì)導(dǎo)致父類的任何變換都可能影響到子類的行為。

如果使用對(duì)象組合,就降低了這種依賴關(guān)系。

7)迪米特法那么(LOD,LawofDemeter)

一個(gè)對(duì)象應(yīng)當(dāng)對(duì)其他對(duì)象盡可能少的了解,從而降低各個(gè)對(duì)象之間的耦合,提高系統(tǒng)的

可維護(hù)性。例如在一個(gè)程序中,各個(gè)模塊之間相互調(diào)用時(shí),通常會(huì)提供一個(gè)統(tǒng)一的接口來(lái)實(shí)

現(xiàn)。這樣其他模塊不需要了解另外一個(gè)模塊的內(nèi)部實(shí)現(xiàn)細(xì)節(jié),這樣當(dāng)一個(gè)模塊內(nèi)部的實(shí)現(xiàn)發(fā)

生改變時(shí),不會(huì)影響其他模塊的使用。(黑盒原理)

案例圖

開閉原那么案例

繁忙

的業(yè)銀行業(yè)務(wù)員

務(wù)員1.付款

2.取款儲(chǔ)戶

3.轉(zhuǎn)賬

4.申購(gòu)基金

5.其他業(yè)務(wù)

負(fù)責(zé)存款負(fù)責(zé)取款負(fù)責(zé)轉(zhuǎn)賬

依賴倒轉(zhuǎn)

1)

傳統(tǒng)的過(guò)程式設(shè)計(jì)傾向于使高層次的模塊依賴于低層次的模塊,抽象層依賴

于具體的層次。

2)

邏輯

業(yè)務(wù)

高層

法那么

迪米特

生人說(shuō)

1)和陌

行解耦

生人進(jìn)

人和陌

讓某

說(shuō)話

生人

象陌

和抽

某人

結(jié)合

那么

轉(zhuǎn)原

賴倒

與依

3)

2創(chuàng)立型模式

2.1單例模式

2.2.1概念

單例模式是一種對(duì)象創(chuàng)立型模式,使用單例模式,可以保證為一個(gè)類只生成唯一的實(shí)例

對(duì)象。也就是說(shuō),在整個(gè)程序空間中,該類只存在一個(gè)實(shí)例對(duì)象。

GOF對(duì)單例模式的定義是:保證一個(gè)類、只有一個(gè)實(shí)例存在,同時(shí)提供能對(duì)該實(shí)例加以

訪問(wèn)的全局訪問(wèn)方法。

單例模式(Singleton)結(jié)構(gòu)圖

Singleton

Singleton類,定義一個(gè)GetInstance操作,允許

-instance:Singleton客戶訪問(wèn)它的唯一實(shí)例Getlnstance是一個(gè)靜態(tài)

-Singleton0方法,主要負(fù)責(zé)創(chuàng)建自己的唯一實(shí)例

+GetInstance0

2.2.2為什么使用單例模式

在應(yīng)用系統(tǒng)開發(fā)中,我們常常有以下需求:

-在多個(gè)線程之間,比方初始化一次socket資源;比方servlet環(huán)境,共享同一個(gè)資源或者

操作同一個(gè)對(duì)象

-在整個(gè)程序空間使用全局變量,共享資源

-大規(guī)模系統(tǒng)中,為了性能的考慮,需要節(jié)省對(duì)象的創(chuàng)立時(shí)間等等。

因?yàn)镾ingleton模式可以保證為一個(gè)類只生成唯一的實(shí)例對(duì)象,所以這些情況,Singleton模

式就派上用場(chǎng)了。

2.2.3實(shí)現(xiàn)單例步驟常用步驟

a)構(gòu)造函數(shù)私有化

b)提供一個(gè)全局的靜態(tài)方法(全局訪問(wèn)點(diǎn))

c)在類中定義一個(gè)靜態(tài)指針,指向本類的變量的靜態(tài)變量指針

2.2.4餓漢式單例和懶漢式單例

懶漢式

#include<iostream>

usingnamespacestd;

〃懶漢式

classSingelton

(

private:

Singelton()

(

m_singer=NULL;

m_count=0;

cout?”構(gòu)造函數(shù)Singelton...do"?endl;

)

public:

staticSingelton*getlnstance()

(

if(m_singer==NULL)〃獺漢式:1每次獲取實(shí)例都要判斷2多線程會(huì)有問(wèn)題

(

m_singer=newSingelton;

}

returnm_singer;

)

staticvoidprintT()

(

cout?"m_count:"?m_count?endl;

)

private:

staticSingelton*m_singer;

staticintm_count;

);

Singelton*Singelton::m_singer=NULL;〃懶漢式并沒(méi)有創(chuàng)立單例對(duì)象

intSingelton::m_count=0;

voidmain01_l()

cout?”演示懶漢式"?endl;

Singelton*pl=Singelton::getlnstance();〃只有在使用的時(shí)候,才去創(chuàng)立對(duì)象。

Singelton*p2=Singelton::getlnstance();

if(pl!=p2)

(

cout?”不是同一個(gè)對(duì)象"?endl;

)

else

(

cout?”是同一個(gè)對(duì)象“?endl;

)

pl->printT();

p2->printT();

system("pause");

return;

llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll

〃俄漢式

classSingelton2

private:

Singelton2()

(

m__singer=NULL;

m_count=0;

cout?”構(gòu)造函數(shù)Singelton...do"?endl;

)

public:

staticSingelton2*getlnstance()

{

//if(m_singer==NULL)

//{

//m_singer=newSingelton2;

//}

returnm_singer;

)

staticvoidSingelton2::Freelnstance()

(

if(m__singer!=NULL)

(

deletem_singer;

m_singer=NULL;

m_count=0;

)

staticvoidprintT()

(

cout?"m_count:"?m_count?endl;

)

private:

staticSingelton2*m_singer;

staticintm_count;

);

Singelton2*Singelton2::m_singer=newSingelton2;〃不管你創(chuàng)立不創(chuàng)立實(shí)例,均把實(shí)例new

出來(lái)

intSingelton2::m_count=0;

voidmain()

(

cout?”演示餓漢式"?endl;

Singelton2*pl=Singelton2::getlnstance();〃只有在使用的時(shí)候,才去創(chuàng)立對(duì)象。

Singelton2*p2=Singelton2::getlnstance();

if(pl!=p2)

cout?"不是同一個(gè)對(duì)象"?endl;

)

else

(

cout?”是同一個(gè)對(duì)象“?endl;

}

pl->printT();

p2->printT();

Singelton2::Freelnstance();

Singelton2::Freelnstance();

system("pause");

2.2.5多線程下的懶漢式單例和餓漢式單例

〃:L"懶漢"模式雖然有優(yōu)點(diǎn),但是每次調(diào)用Getlnstance()靜態(tài)方法時(shí),必須判斷

//NULL==mjnstance,使程序相對(duì)開銷增大。

//2多線程中會(huì)導(dǎo)致多個(gè)實(shí)例的產(chǎn)生,從而導(dǎo)致運(yùn)行代碼不正確以及內(nèi)存的泄露。

//3提供釋放資源的函數(shù)

討論:這是因?yàn)镃++中構(gòu)造函數(shù)并不是線程平安的。

C++中的構(gòu)造函數(shù)簡(jiǎn)單來(lái)說(shuō)分兩步:

第一步:內(nèi)存分配

第二步:初始化成員變量

由于多線程的關(guān)系,可能當(dāng)我們?cè)诜峙鋬?nèi)存好了以后,還沒(méi)來(lái)得急初始化成員變量,

就進(jìn)行線程切換,另外一個(gè)線程拿到所有權(quán)后,由于內(nèi)存已經(jīng)分配了,但是變量初始化還

沒(méi)進(jìn)行,因此打印成員變量的相關(guān)值會(huì)發(fā)生不一致現(xiàn)象.

多線程下的懶漢式問(wèn)題拋出:

mainINFINITE).

該函:?數(shù)作用.

告訴內(nèi)核,客待子線程部結(jié)束完畢以

'后,:才把主進(jìn)程main,給陜醒,指向

linux:pthread_create(..,緩?fù)撕痼w)2)進(jìn)程結(jié)束了

上層應(yīng)用

WaitForSingleObject

核win內(nèi)核

1次調(diào)用2次返回

2寫時(shí)復(fù)制

子進(jìn)程和父進(jìn)程在各自的進(jìn)程空間

內(nèi)返回...

進(jìn)程空間:堆棧的內(nèi)存四區(qū)

#include"stdafx.h"

#include"windows.h"

include"winbase.h"

#include<process.h>

#include"iostream"

usingnamespacestd;

classSingelton

(

private:

Singelton()

(

count++;

cout?"Singelton構(gòu)造函數(shù)begin\n"?endl;

Sleep(lOOO);

cout?"Singelton構(gòu)造函數(shù)end\n"?endl;

)

private:

〃防止拷貝構(gòu)造和賦值操作

Singelton(constSingelton&obj){;}

Singelton&operator=(constSingelton&obj){;}

public:

staticSingelton*getSingelton()

(

〃。懶漢”模式雖然有優(yōu)點(diǎn),但是每次調(diào)用Getlnstance。靜態(tài)方法時(shí),必須判斷

//NULL==m_instance,使程序相對(duì)開銷增大。

//2多線程中會(huì)導(dǎo)致多個(gè)實(shí)例的產(chǎn)生,從而導(dǎo)致運(yùn)行代碼不正確以及內(nèi)存的泄露。

//3提供釋放資源的函數(shù)

returnsingle;

)

staticSingelton*releaseSingelton()

(

if(single!=NULL)〃需要判斷

(

釋放資源\n“《endl;

deletesingle;

single=NULL;

}

returnsingle;

)

voidpirntS()〃測(cè)試函數(shù)

(

printf("Singeltonprintstestcount:%d\n",count);

)

private:

staticSingelton*single;

staticintcount;

);

//note靜態(tài)變量類外初始化

Singelton*Singelton::single=newSingelton();

intSingelton::count=0;

int_tmainTTT(intargc,_TCHAR*argv[])

(

Singelton*sl=Singelton::getSingelton();

Singelton*s2=Singelton::getSingelton();

if(si==s2)

(

cout?"ok....equal"?endl;

)

else

(

cout?,'not.equal"?endl;

}

sl->pirntS();

Singelton::releaseSingelton();

cout?"hello...."?endl;

system("pause");

return0;

)

unsignedintthreadfunc2(void*mylpAdd)

intid=GetCurrentThreadld();

printf("\nthreadfunc%dXn",id);

return1;

)

voidthreadfunc(void*mylpAdd)

(

intid=GetCurrentThreadld();

printf("\nthreadfunc%d\n",id);

Singelton::getSingelton()->pirntS();

return;

)

int_tmain(intargc,__TCHAR*argv[])

(

inti=0;

DWORDdwThreadld[201],dwThrdParam=1;

HANDLEhThread[201];

intthreadnum=3;

for(i=0;i<threadnum;i++)

(

//hThread[i]=(HANDLE)_beginthreadex(NULL,&threadfunczNULL,

0,&dwThreadld[i]);

hThread[i]=(HANDLE)_beginthread(&threadfunc,0,0);

if(hThread[i]==NULL)

printf("beginthread%derror!!!\n",i);

break;

)

)

〃等待所有的子線程都運(yùn)行完畢后,才執(zhí)行這個(gè)代碼

for(i=0;i<threadnum;i++)

(

WaitForSingleObject(hThread[i],INFINITE);

}

printf(“等待線程結(jié)束\n“);

for(i=0;i<threadnum;i++)

(

//CloseHandle(hThread[i]);

}

Singelton::releaseSingelton();

cout?"hello...."?endl;

system("pause");

return0;

}

2.2.6多線程下懶漢式單例的Double-CheckedLocking優(yōu)化

新建MFC對(duì)話框應(yīng)用程序。

方便使用臨界區(qū)類對(duì)象,同步線程

//MFCDiagram應(yīng)用程序

#include"stdafx.h"

#include”01單例優(yōu)化.h"

#include"01單例優(yōu)化Dlg.h"

#include"afxdialogex.h"

#include"iostream"

usingnamespacestd;

〃臨界區(qū)

staticCCriticalSectioncs;

//manpthread_create()

classSingleton

(

private:

Singleton()

(

TRACE("Singletonbegin\n");

Sleep(lOOO);

TRACE("Singletonend\n");

)

Singleton(constSingleton&);

Singleton&operator=(constSingleton&);

public:

staticvoidprintV()

(

TRACE("printV..\n");

)

〃請(qǐng)思考;懶漢式的Double-Check是一個(gè)經(jīng)典問(wèn)題!為什么需要2次檢查“if(plnstance==

NULL)”

場(chǎng)景:假設(shè)有線程1、線程2、線程3,同時(shí)資源競(jìng)爭(zhēng)。

//1)第1個(gè)、2個(gè)、3個(gè)線程執(zhí)行第一個(gè)檢查,都有可能進(jìn)入黃色區(qū)域(臨界區(qū))

〃2)假設(shè)第1個(gè)線程進(jìn)入到臨界區(qū),第2個(gè)、第3個(gè)線程需要等待

〃3)第1個(gè)線程執(zhí)行完畢,cs.unlock()后,第2個(gè)、第3個(gè)線程要競(jìng)爭(zhēng)執(zhí)行臨界區(qū)代碼。

〃4)假假設(shè)第2個(gè)線程進(jìn)入臨界區(qū),此時(shí)第2個(gè)線程需要再次判斷if(plnstance==NULL)",

假設(shè)第一個(gè)線程已經(jīng)創(chuàng)立實(shí)例;第2個(gè)線程就不需要再次創(chuàng)立了。保證了單例;

//5)同樣道理,假設(shè)第2個(gè)線程,cs.unlock。后,第3個(gè)線程會(huì)競(jìng)爭(zhēng)執(zhí)行臨界區(qū)代碼;此時(shí)

第3個(gè)線程需要再次判斷if(plnstance==NULL)?通過(guò)檢查發(fā)現(xiàn)實(shí)例已經(jīng)new出來(lái),就不需

要再次創(chuàng)立;保證了單例。

staticSingleton*lnstantialize()

{

iffplnstance==NULL)//doublecheck

(

cs.Lock();〃只有當(dāng)plnstance等于null時(shí),才開始使用加鎖機(jī)制二次檢查

if(plnstance==NULL)

plnstance=newSingleton();

)

cs.Unlock();

}

returnplnstance;

)

staticSingleton*plnstance;

);

Singleton*Singleton::plnstance=0;

voidCMyOl單例優(yōu)化Dlg::OnBnClickedButtonl()

(

CCriticalSectioncs;

cs.Lock();

cs.Unlock();

//TODO:在此添加控件通知處理程序代碼

)

voidthreadfunc(void*mylpAdd)

intid=GetCurrentThreadld();

TRACE("\nthreadfunc%d\n",id);

Singleton::lnstantialize()->printV();

//Singelton::getSingelton()->pirntS();

)

voidCMyOl單例優(yōu)化Dlg::OnBnClickedButton2()

(

inti=0;

DWORDdwThreadld[201]/dwThrdParam=1;

HANDLEhThread[201];

intthreadnum=3;

for(i=0;i<threadnum;i++)

|

//hThread[i]=(HANDLE)_beginthreadex(NULL,0,&threadfunc,NULL,

0,&dwThreadld[i]);

hThread[i]=(HANDLE)_beginthread(&threadfunc,0,0);

if(hThread[i]==NULL)

(

TRACE("beginthread%derror!i);

break;

)

}

for(i=0;i<threadnum;i++)

WaitForSingleObject(hThread[i],INFINITE);

}

TRACE("等待線程結(jié)束\n");

for(i=0;i<threadnum;i++)

//CloseHandle(hThread[i]);

}

//Singelton::releaseSingelton();

TRACE("ddddd\n");

2.2.7程序并發(fā)機(jī)制擴(kuò)展閱讀

程序的并發(fā)執(zhí)行往往帶來(lái)與時(shí)間有關(guān)的錯(cuò)誤,甚至引發(fā)災(zāi)難性的后果。這需要

引入同步機(jī)制。使用多進(jìn)程與多線程時(shí),有時(shí)需要協(xié)同兩種或多種動(dòng)作,此過(guò)程就

稱同步(Synchronization引入同步機(jī)制的第一個(gè)原因是為了控制線程之間的資源

同步訪問(wèn),因?yàn)槎鄠€(gè)線程在共享資源時(shí)如果發(fā)生訪問(wèn)沖突通常會(huì)帶來(lái)不正確的后果。

例如,一個(gè)線程正在更新一個(gè)結(jié)構(gòu),同時(shí)另一個(gè)線程正試圖讀取同一個(gè)結(jié)構(gòu)。結(jié)果,

我們將無(wú)法得知所讀取的數(shù)據(jù)是新的還是舊的,或者是二者的混合。第二個(gè)原因是

有時(shí)要求確保線程之間的動(dòng)作以指定的次序發(fā)生,如一個(gè)線程需要等待由另外一個(gè)

線程所引起的事件。

為了在多線程程序中解決同步問(wèn)題,Windows提供了四種主要的同步對(duì)象,

每種對(duì)象相對(duì)于線程有兩種狀態(tài)一一信號(hào)狀態(tài)(signalstate)和非信號(hào)狀態(tài)(nonsignal

state)?當(dāng)相關(guān)聯(lián)的同步對(duì)象處于信號(hào)狀態(tài)時(shí),線程可以執(zhí)行(訪問(wèn)共享資源),反

之必須等待。這四種同步對(duì)象是:

(1)事件對(duì)象(Event)。事件對(duì)象作為標(biāo)志在線程間傳遞信號(hào)。一個(gè)或多個(gè)線

程可等待一個(gè)事件對(duì)象,當(dāng)指定的事件發(fā)生時(shí),事件對(duì)象通知等待線程可以開始執(zhí)

行。它有兩種類型:自動(dòng)重置(auto-reset)事件和手動(dòng)重置(manual-reset)事件。

⑵臨界區(qū)(CriticalSection).臨界區(qū)對(duì)象通過(guò)提供一個(gè)進(jìn)程內(nèi)所有線程必須

共享的對(duì)象來(lái)控制線程。只有擁有那個(gè)對(duì)象的線程可以訪問(wèn)保護(hù)資源。在另一個(gè)線

程可以訪問(wèn)該資源之前,前一個(gè)線程必須釋放臨界區(qū)對(duì)象,以便新的線程可以索取

對(duì)象的訪問(wèn)權(quán)。

(3)互斥量(MutexSemaphore)。互斥量的工作方式非常類似于臨界區(qū),只是

互斥量不僅保護(hù)一個(gè)進(jìn)程內(nèi)為多個(gè)線程使用的共享資源,而且還可以保護(hù)系統(tǒng)中兩

個(gè)或多個(gè)進(jìn)程之間的的共享資源。

(4)信號(hào)量(Semaphore)。信號(hào)量可以允許一個(gè)或有限個(gè)線程訪問(wèn)共享資源。

它是通過(guò)計(jì)數(shù)器來(lái)實(shí)現(xiàn)的,初始化時(shí)賦予計(jì)數(shù)器以可用資源數(shù),當(dāng)將信號(hào)量提供應(yīng)

一個(gè)線程時(shí),計(jì)數(shù)器的值減1,當(dāng)一個(gè)線程釋放它時(shí),計(jì)數(shù)器值加1。當(dāng)計(jì)數(shù)器值小

于等于0時(shí),相應(yīng)線程必須等待。信號(hào)量是Windows98同步系統(tǒng)的核心。從本質(zhì)上

講,互斥量是信號(hào)量的一種特殊形式。

Windows/NT還提供了另外一種Windows95沒(méi)有的同步對(duì)象:可等待定時(shí)器

(WaitableTimer)o它可以封鎖線程的執(zhí)行,直到到達(dá)某一具體時(shí)間。這可以用于

后臺(tái)任務(wù)。

同步問(wèn)題是多線程編程中最復(fù)雜的問(wèn)題,后面的linux系統(tǒng)編程中,還會(huì)有更深入的介紹。

2.2.8總結(jié)

在很多人印象中,單例模式可能是23個(gè)設(shè)計(jì)模式中最簡(jiǎn)單的一個(gè)。如果不考慮多線程,的

確如此,但是一旦要在多線程中運(yùn)用,那么從我們的教程中可以了解到,它涉及到很多

譯器,多線程,C++語(yǔ)言標(biāo)準(zhǔn)等方面的內(nèi)容。本專題參考的資料如下:

1、C++Primer(StanleyB.Lippman),主要參考的是模板靜態(tài)變量的初始化以及實(shí)例化。

2、MSDN,有關(guān)線程同步interlocked相關(guān)的知識(shí)。

3、EffectiveC++04條款(ScottMeyers)Non-Local-Static對(duì)象初始化順序以及Meyers

單例模式的實(shí)現(xiàn)。

4、Double-CheckedLocking,Threads,CompilerOptimizations,andMore(Scott

Meyers),解釋了由于編譯器的優(yōu)化,導(dǎo)致auto_ptr.reset函數(shù)不平安,shared_ptr

有類似情況。我們防止使用reset函數(shù)。

5、C++全局和靜態(tài)變量初始化順序的研究(CSDN)。

6、四人幫的經(jīng)典之作:設(shè)計(jì)模式

7、windows核心編程(JeffreyRichter)

2.2簡(jiǎn)單工廠模式

221什么是簡(jiǎn)單工廠模式

簡(jiǎn)單工廠模式屬于類的創(chuàng)立型模式,又叫做靜態(tài)工廠方法模式。通過(guò)專門定義一個(gè)類來(lái)負(fù)

責(zé)創(chuàng)立其他類的實(shí)例,被創(chuàng)立的實(shí)例通常都具有共同的父類。

2.2.2模式中包含的角色及其職責(zé)

1.工廠(Creator)角色

簡(jiǎn)單工廠模式的核心,它負(fù)責(zé)實(shí)現(xiàn)創(chuàng)立所有實(shí)例的內(nèi)部邏輯。工廠類可以被外界直接調(diào)

用,創(chuàng)立所需的產(chǎn)品對(duì)象。

2.抽象(Product)角色

簡(jiǎn)單工廠模式所創(chuàng)立的所有對(duì)象的父類,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口。

3.具體產(chǎn)品(ConcreteProduct)角色

簡(jiǎn)單工廠模式所創(chuàng)立的具體實(shí)例對(duì)象

〃依賴:一個(gè)類的對(duì)象當(dāng)另外一個(gè)類的函數(shù)參數(shù)或者是返回值

3簡(jiǎn)單工廠模式的優(yōu)缺點(diǎn)

在這個(gè)模式中,工廠類是整個(gè)模式的關(guān)鍵所在。它包含必要的判斷邏輯,能夠根據(jù)外界

給定的信息,決定究竟應(yīng)該創(chuàng)立哪個(gè)具體類的對(duì)象。用戶在使用時(shí)可以直接根據(jù)工廠類去創(chuàng)

立所需的實(shí)例,而無(wú)需了解這些對(duì)象是如何創(chuàng)立以及如何組織的。有利于整個(gè)軟件體系結(jié)構(gòu)

的優(yōu)化。不難發(fā)現(xiàn),簡(jiǎn)單工廠模式的缺點(diǎn)也正表達(dá)在其工廠類上,由于工廠類集中了所有實(shí)

例的創(chuàng)立邏輯,所以“高內(nèi)聚”方面做的并不好。另外,當(dāng)系統(tǒng)中的具體產(chǎn)品類不斷增多時(shí),

可能會(huì)出現(xiàn)要求工廠類也要做相應(yīng)的修改,擴(kuò)展性并不很好。

2.2.3案例

include"iostream"

usingnamespacestd;

〃思想:核心思想是用一個(gè)工廠,來(lái)根據(jù)輸入的條件產(chǎn)生不同的類,然后根據(jù)不同類的virtual

函數(shù)得到不同的結(jié)果。

〃元素分析:

〃抽象產(chǎn)品類:水果類

〃具體的水果了:香蕉類、蘋果類、梨子

〃優(yōu)點(diǎn)適用于不同情況創(chuàng)立不同的類時(shí)

〃缺點(diǎn)客戶端必須要知道基類和工廠類,耦合性差增加一個(gè)產(chǎn)品,需要修改工廠類

classFruit

(

public:

virtualvoidgetFruit()=0;

protected:

private:

};

classBanana:publicFruit

(

public:

virtualvoidgetFruit()

(

cout<<"香蕉“<<endl;

}

protected:

private:

);

classPear:publicFruit

(

public:

virtualvoidgetFruit()

(

cout<<“梨子”<<endl;

)

protected:

private:

);

classFactory

(

public:

staticFruit*Create(char*name)

{

Fruit*tmp=NULL;

if(strcmpfname,"pear")==0)

(

tmp=newPear();

)

elseif(strcmpfname,"banana")==0)

(

tmp=newBanana();

)

else

(

returnNULL;

}

returntmp;

)

protected:

private:

);

voidmain41()

(

Fruit*pear=Factory::Create("pear");

if(pear==NULL)

{

cout<<"創(chuàng)立pear失敗\n”;

}

pear->getFruit();

Fruit*banana=Factory::Create("banana");

banana->getFruit();

system("pause");

2.2.4練習(xí)

主要用于創(chuàng)立對(duì)象。新添加類時(shí),不會(huì)影響以前的系統(tǒng)代碼。核心思想是用一個(gè)工廠來(lái)根據(jù)

輸入的條件產(chǎn)生不同的類,然后根據(jù)不同類的virtual函數(shù)得到不同的結(jié)果。

GOOD:適用于不同情況創(chuàng)立不同的類時(shí)

BUG:客戶端必須要知道基類和工廠類,耦合性差

?*IT?

(工廠類與基類為關(guān)聯(lián)關(guān)系〕

#include"iostream"

usingnamespacestd;

〃需求:〃模擬四那么運(yùn)算;

〃用操作符工廠類生產(chǎn)操作符(加減乘除),進(jìn)行結(jié)果運(yùn)算

〃運(yùn)算符抽象類COperation

〃加減乘除具體的類(注意含有2個(gè)操作數(shù))

〃工廠類CCalculatorFactory

〃核心思想用一個(gè)工廠來(lái)根據(jù)輸入的條件產(chǎn)生不同的類,然后根據(jù)不同類的virtual函數(shù)得

到不同的結(jié)果

classCOperation

public:

intfirst;

intsecond;

public:

virtualdoubleGetResult()=0;

private:

);

classAddOperation:publicCOperation

(

public:

doubleGetResult()

(

returnfirst+second;

)

private:

);

classSubOperation:publicCOperation

(

public:

doubleGetResult()

(

returnfirst-second;

)

private:

);

classCCalculatorFactory

(

public:

staticCOperation*CreateOperation(charcOperator)

(

COperation*tmp=NULL;

switch(cOperator)

(

case

tmp=newAddOperation();

break;

case,J:

tmp=newSubOperation();

break;

default:

tmp=NULL;

}

returntmp;

)

);

voidmain()

COperation*opl=CCalculatorFactory::CreateOperation('+');

opl->first=10;

opl->second=20;

cout?opl->GetResult()?endl;

COperation*op2=CCalculatorFactory::CreateOperation('-');

op2->first=10;

op2->second=20;

cout?op2->GetResult()?endl;

cout?"hello...\n";

system("pause");

}

2.3工廠模式

2.3.1概念

工廠方法模式同樣屬于類的創(chuàng)立型模式又被稱為多態(tài)工廠模式。工廠方法模式的意義是

定義一個(gè)創(chuàng)立產(chǎn)品對(duì)象的工廠接口,將實(shí)際創(chuàng)立工作推遲到子類當(dāng)中。

核心工廠類不再負(fù)責(zé)產(chǎn)品的創(chuàng)立,這樣核心類成為一個(gè)抽象工廠角色,僅負(fù)責(zé)具體工廠子類

必須實(shí)現(xiàn)的接口,這樣進(jìn)一步抽象化的好處是使得工廠方法模式可以使系統(tǒng)在不修改具體工

廠角色的情況下引進(jìn)新的產(chǎn)品。

2.3.2類圖角色和職責(zé)

抽象工廠(Creator)角色

工廠方法模式的核心,任何工廠類都必須實(shí)現(xiàn)這個(gè)接口。

具體工廠(ConcreteCreator)角色

具體工廠類是抽象工廠的一個(gè)實(shí)現(xiàn),負(fù)責(zé)實(shí)例化產(chǎn)品對(duì)象。

抽象(Product)角色

工廠方法模式所創(chuàng)立的所有對(duì)象的父類,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口。

具體產(chǎn)品(ConcreteProduct)角色

工廠方法模式所創(chuàng)立的具體實(shí)例對(duì)象

工廠方法模式(FactoryMethod)結(jié)構(gòu)圖

2.3.3工廠方法模式和簡(jiǎn)單工廠模式比擬

工廠方法模式與簡(jiǎn)單工廠模式在結(jié)構(gòu)上的不同不是很明顯。工廠方法類的核心是一個(gè)抽

象工廠類,而簡(jiǎn)單工廠模式把核心放在一個(gè)具體類上。

工廠方法模式之所以有一個(gè)別名叫多態(tài)性工廠模式是因?yàn)榫唧w工廠類都有共同的接口,

或者有共同的抽象父類。

當(dāng)系統(tǒng)擴(kuò)展需要添加新的產(chǎn)品對(duì)象時(shí),僅僅需要添加一個(gè)具體對(duì)象以及一個(gè)具體工廠對(duì)

象,原有工廠對(duì)象不需要進(jìn)行任何修改,也不需要修改客戶端,很好的符合了“開放一封閉”

原那么。而簡(jiǎn)單工廠模式在添加新產(chǎn)品對(duì)象后不得不修改工廠方法,擴(kuò)展性不好。工廠方法

模式退化后可以演變成簡(jiǎn)單工廠模式。

“開放一封閉"通過(guò)添加代碼的方式,不是通過(guò)修改代碼的方式完成功能的增強(qiáng)。

#include"iostream"

usingnamespacestd;

classFruit

(

public:

virtualvoidsayname()

(

cout?"fruit\n";

)

);

classFruitFactory

(

public:

virtualFruit*getFruitf)

(

returnnewFruit();

)

);

〃香蕉

classBanana:publicFruit

{

public:

virtualvoidsayname()

cout?"Banana\n"?endl;

}

);

〃香蕉工廠

classBananaFactory:publicFruitFactory

(

public:

virtualFruit*getFruit()

(

returnnewBanana;

)

);

〃蘋果

classApple:publicFruit

(

public:

virtualvoidsayname()

cout?"Apple\n"?endl;

)

);

〃蘋果工廠

classAppleFactory:publicFruitFactory

(

public:

virtualFruit*getFruit()

(

returnnewApple;

}

);

voidmain()

(

FruitFactory*ff=NULL;

Fruit*fruit=NULL;

//I

ff=newBananaFactory();

fruit=ff->getFruit();

fruit->sayname();

deletefruit;

deleteff;

〃2蘋果

ff=newAppleFactoryO;

fruit=ff->getFruit();

fruit->sayname();

deletefruit;

deleteff;

cout?"hello....\n";

system("pause");

2.4抽象工廠

2.4.1概念

抽象工廠模式是所有形態(tài)的工廠模式中最為抽象和最其一般性的。抽象工廠模式可以向

客戶端提供一個(gè)接口,使得客戶端在不必指定產(chǎn)品的具體類型的情況下,能夠創(chuàng)立多個(gè)產(chǎn)品

族的產(chǎn)品對(duì)象。

2.4.2產(chǎn)品族和產(chǎn)品等級(jí)結(jié)構(gòu)

產(chǎn)品族

備注1:工廠模式:要么生產(chǎn)香蕉、要么生產(chǎn)蘋果、要么生產(chǎn)西紅柿;但是不能同時(shí)生產(chǎn)一

個(gè)產(chǎn)品組。抽象工廠:能同時(shí)生產(chǎn)一個(gè)產(chǎn)品族。===?抽象工廠存在原因

解釋:具體工廠在開閉原那么下,能生產(chǎn)香蕉/蘋果/梨子;(產(chǎn)品等級(jí)結(jié)構(gòu))

抽象工廠:在開閉原那么下,能生產(chǎn):南方香蕉/蘋果/梨子(產(chǎn)品族)

北方香蕉/蘋果/梨子

重要區(qū)別:

工廠模式只能生產(chǎn)一個(gè)產(chǎn)品。(要么香蕉、要么蘋果)

抽象工廠可以一下生產(chǎn)一個(gè)產(chǎn)品族(里面有很多產(chǎn)品組成)

2.4.3模式中包含的角色及其職責(zé)

1.抽象工廠(Creator)角色

抽象工廠模式的核心,包含對(duì)多個(gè)產(chǎn)品結(jié)構(gòu)的聲明,任何工廠類都必須實(shí)現(xiàn)這個(gè)接口。

2.具體工廠(ConcreteCreator)角色

具體工廠類是抽象工廠的一個(gè)實(shí)現(xiàn),負(fù)責(zé)實(shí)例化某個(gè)產(chǎn)品族中的產(chǎn)品對(duì)象。

3.抽象(Product)角色

抽象模式所創(chuàng)立的所有對(duì)象的父類,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口。

4.具體產(chǎn)品(ConcreteProduct)角色

抽象模式所創(chuàng)立的具體實(shí)例對(duì)象

抽象工廠模式(AbstractFactory)結(jié)構(gòu)圖

2.4.4案例

classFruit

(

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論