GeekBand C++ Week9 Notes

C++設(shè)計模式

為了理解松耦合設(shè)計思想,掌握面向?qū)ο笤O(shè)計原則

什么是設(shè)計模式等孵?

是一種解決方案的核心,可以避免重復(fù)勞動

設(shè)計模式不等于面向?qū)ο笤O(shè)計模式

底層思維:向下,如何把握機器底層從微觀理解對象構(gòu)造

語言構(gòu)造炫乓,變易轉(zhuǎn)換

內(nèi)存模型

運行時機制

抽象思維:向上,如何將我們的現(xiàn)實世界抽象為程序代碼砂豌,

面向?qū)ο?/p>

組件封裝

設(shè)計模式

架構(gòu)模式

深入理解面向?qū)ο螅?/p>

向下:封裝厢岂,繼承,多態(tài)

向上:深刻把握面向?qū)ο髾C制所帶來的抽象意義阳距,理解如何利用這些機制來表達現(xiàn)實世界塔粒,掌握什么是好的面向?qū)ο笤O(shè)計

如何解決復(fù)雜性?

分解筐摘,人們面對復(fù)雜性有一個常見的做法:分而治之卒茬,將大問題分解為多個小問題船老,將復(fù)雜問題分解為多個簡單問題

抽象:更高層次來講,人們處理復(fù)雜性有一個通用的技術(shù)圃酵,由于不能掌握全部的復(fù)雜對象柳畔,我們選擇忽視它的非本質(zhì)性細節(jié)而去處理泛化和理想化了的模型

class Point{

public:

? ? intx;

? ? int y;

};

class Line{

public:

? ? Pointstart;

? ? Pointend;

? ? Line(constPoint& start, const Point& end, ){

? ? ? ? This->start= start;

? ? ? ? This->end= end; ?

? ? }

};

抽象的過程

在shape里面有虛擬方法draw,一個形狀負責(zé)畫自己,實現(xiàn)自己的draw.

在子類中overide自己父類的虛函數(shù)

virtual void Draw(const Graphics& g){

g.DrawLine(Pens,Red, start.x, start.y, end.x, end.y);

}

class MainForm:public Form{

private:

pointp1;

point p2;

vector

shapeVector;//多態(tài)

public:

}

在后面對shapevector中的元素進行多態(tài)調(diào)用郭赐。

兩種方法的區(qū)別薪韩,哪種更好?

客戶需求的變化:

如果客戶需要多加一個圓

//增加一個類

class Circle{

};

在mainform里增加一個

vector CircleVector

如果檢測到要畫圓則要判斷將圓push——back到圓的vector里

然后刷新以后捌锭,要把圓顯示出來

用抽象的方法俘陷,建立新的circle類

class Circle: public shape{

public:

//負責(zé)自己的draw

}

vector不需要動,因為是shape*指針

全都不用改變除了刷新

工廠模式里在刷新一個圓的時候也不需要改變

重用性得到了很高的提升

當(dāng)需求變化的時候观谦,更加方便

DRY@堋!豁状!

由于不能掌握全部的復(fù)雜對象捉偏,處理泛化的問題

面向?qū)ο蟮脑O(shè)計原則

變化是復(fù)用的天敵,面向?qū)ο笤O(shè)計最大的優(yōu)勢在于抵御變化泻红。

理解隔離變化

從宏觀層面來看夭禽,面向?qū)ο蟮臉?gòu)建方式更能適應(yīng)軟件的變化,能將變化所帶來的影響減為最小承桥。

各司其職

從微觀層面來看驻粟,面向?qū)ο蟮姆绞礁鼜娬{(diào)個各類的責(zé)任

在第一個例子里,畫線的責(zé)任從mainform到了形狀自己凶异,接口一樣但實際不一樣蜀撑。

對象是什么?

從語言實現(xiàn)層面來看剩彬,對象封裝了代碼和數(shù)據(jù)酷麦,

從規(guī)格層面來看,對象是一系列可以被使用的公共接口

從概念層面來看喉恋,

面向?qū)ο蟮脑O(shè)計原則//設(shè)計原則比模式更重要

依賴倒置原則(DIP)

高層模塊(穩(wěn)定)不應(yīng)該依賴于低層模塊(變化)沃饶,二者都應(yīng)該依賴于抽象(穩(wěn)定)

抽象(穩(wěn)定)不應(yīng)該依賴于實現(xiàn)細節(jié)(變化),實現(xiàn)細節(jié)應(yīng)該依賴于抽象(穩(wěn)定)轻黑。

開放封閉原則(OCP)

對擴展開放糊肤,對更改封閉

類模塊應(yīng)該是可擴展的,但是不可以修改

單一職責(zé)原則(SRP)

一個類應(yīng)該僅有一個引起它變化的原因

變化的方向隱含著類的責(zé)任

Liskov替換原則(LSP)

子類必須能夠替換它們的基類(IS-A)

繼承表達類型抽象

接口隔離原則(ISP)

不應(yīng)該強迫客戶程序依賴它們不用的方法

接口應(yīng)該小而完備

優(yōu)先使用對象組合氓鄙,而不是類繼承

類繼承通常為白箱復(fù)用馆揉,對象組合通常為黑箱復(fù)用。

繼承在某種程度上破壞了封裝性抖拦,子類父類耦合度高

而對象組合則只要求被組合的對象具有良好定義的接口升酣,耦合度低舷暮。

封裝變化點

使用封裝來創(chuàng)建對象之間的分界層,讓設(shè)計者可以在分界層的一側(cè)進行修改噩茄,而不會對另一側(cè)產(chǎn)生不良影響下面。

針對接口編程,而不是針對實現(xiàn)編程绩聘。

不將變量類型聲明為具體的類沥割,而是聲明為某個接口,客戶程序無需知道對象的具體類型凿菩,只需要知道對象所具有的接口驯遇。

減少系統(tǒng)中各部分的依賴關(guān)系,從而實現(xiàn)“高內(nèi)聚蓄髓,低耦合”類型的設(shè)計方案。

產(chǎn)業(yè)強盛的標(biāo)志:接口標(biāo)準(zhǔn)化

模板方法

Template Method

GOF-23模式分類

設(shè)計模式的應(yīng)用不應(yīng)該先入為主舒帮,一上來就使用設(shè)計模式是對設(shè)計模式最大的誤用会喝,沒有一步到位的設(shè)計模式。

重構(gòu)的關(guān)鍵技法:

靜態(tài)到動態(tài)玩郊,早綁定到晚綁定肢执,繼承到組合,編譯時依賴到運行時依賴译红,緊耦合到松耦合

組件協(xié)作模式:

框架與應(yīng)用程序的劃分预茄,組合協(xié)作模式通過晚期綁定,來實現(xiàn)框架和應(yīng)用程序之間的松耦合侦厚,是二者之間協(xié)作時常用的模式耻陕。

典型模式:

template method

strategy

observer/event

動機:在軟件構(gòu)件過程中,某項任務(wù)常常有穩(wěn)定的整體操作結(jié)構(gòu)刨沦,但各個子步驟卻有很多改變的需求诗宣,或者由于固有的原因,比如框架和應(yīng)用之間的關(guān)系想诅,而無法和任務(wù)的整體機構(gòu)同時實現(xiàn)

class library{

public:

? ? voidstep1(){?

? ? //…

? ? }

? ? voidstep3(){

? ? //…

? ? }

? ? void step5(){

? ? }

};//程序庫開發(fā)人員

class Application{

? ? voidstep2{

? ? }

? ? void step4{

? ? }

};

int main(){

? ? Librarylib();

? ? Applicationapp();

? ? Lib.step1(); ??

? ? If(app.step2()){

? ? ? ? Lib.step3();

? ? }

….

}

另外一種做法:

庫的開發(fā)人員

除了1召庞,3,5来破,也寫step2和step4

virtualbool step2(){}

virtualvoid step4(){}

把run()寫在類里篮灼,1,3徘禁,5是protected,虛的析構(gòu)函數(shù)诅诱。

子類重寫實現(xiàn)

library* pLIb = new Apllication();

plib->run();

delete plib;

前一種方法lib開發(fā)人員開發(fā)1,3晌坤,5三個步驟逢艘,app開發(fā)人員開發(fā)2旦袋,4兩個步驟,和程序主流程

另一種lib開發(fā)人員寫1它改,3疤孕,5三個步驟和程序主流程,app開發(fā)人員開發(fā)2央拖,4兩個步驟祭阀。

第一種是app調(diào)用lib的,第二種是lib的調(diào)用app的

第一種寫法是一種早綁定的寫法鲜戒,因為lib一般寫的早专控,程序庫寫的早。晚的東西調(diào)用早的東西遏餐,但在面向?qū)ο笳Z言中伦腐,有晚綁定的機制,lib寫的早但是它調(diào)用app失都,所以是晚綁定柏蘑。模式定義一個操作算法的骨架(穩(wěn)定),而將一些步驟延遲到子類中粹庞,template method是的子類可以不改變一個算法結(jié)構(gòu)即可以重定義override咳焚,重寫該算法的某些特定步驟。

為什么叫template method?run就是一個樣板

穩(wěn)定中有變化庞溜,2革半,4支持變化,是虛函數(shù)的多態(tài)調(diào)用

c++中穩(wěn)定的要寫成非虛函數(shù)流码,變化的要寫成虛函數(shù)

設(shè)計模式的假定條件是必須有一個穩(wěn)定點

也一定有變化又官,設(shè)計模式的最大的作用就是在穩(wěn)定和變化之間尋找一個平衡點,把兔子關(guān)進籠子里漫试。

在具體實現(xiàn)方面赏胚,被template method調(diào)用的虛方法可以具有實現(xiàn),也可以沒有任何實現(xiàn)(抽象方法商虐,虛方法)觉阅,但一般推薦把它們設(shè)置為protected方法。

“不要調(diào)用我秘车,讓我來調(diào)用你”的反向控制結(jié)構(gòu)典勇。

策略模式:

strategy策略模式是一個組件協(xié)作類的模式,實現(xiàn)框架和應(yīng)用程序之間的松耦合

動機:在軟件構(gòu)件過程中叮趴,有些對象使用的算法可能多種多樣經(jīng)常改變割笙,如果將這些算法都編碼到對象中,將會使對象變得復(fù)雜,有時候支持不適用的算法也是一個性能負擔(dān)伤溉,透明得更改般码,使算法和對象解耦。

Enum taxbase{

CN_Tax,

Us_tAX

dE_TAX

};

class SalesOrder{

? ? texbasetax;

public:

? ? doublecalculateTax(){

? ? if(tax== cn_tax){

? ? }

? ? else if(tax ==us_tax){

? ? }

? ? else if(tax==de_tax){

? ? }

}

};

有沒有可能未來支持其他國家的稅法

class taxStrategy{

public:

virtualdouble calculate(const context& context) = 0;

virtual~taxstrategy(){}

};

class CNTax:public taxstrategy{

public:

virtualdouble calculate(const context& context){}

};

class ustax: public taxstrategy{

public:

virtualdouble calculate(const context& context){}

};

class salesorder{

private:

taxstrategy*strategy;

public:

salesorder(strategyfactory*strategyfactory){

this->strategy= strategyfactory->newstrategy();

}

~salesorder(){}

public doublecalculatetax(){

contextcontext();

double val =

strategy->calculate(context);//多態(tài)調(diào)用

}

};

把一些列算法一個個封裝起來并且使他們可以互相替換乱顾,是算法獨立于客戶程序(穩(wěn)定)而變化(擴展板祝,子類化)

strategy使類型在運行時方便地根據(jù)需要在各個算法之間切換

strategy模式提供了用條件判斷語句以外的另一種選擇,消除條件判斷語句實在解耦合走净。

如果Strategy對象沒有實例變量券时,各個上下文可以共享一個strategy變量,從而節(jié)省對象開銷伏伯。

有很多ifelse代碼不會被真正使用但是要存在緩存里橘洞,使得有用的代碼被擠到主存里,但這個不是主要的好處说搅。

Observer/event觀察者模式

動機:需要為某些對象建立一種通知依賴關(guān)系-一個對象的狀態(tài)發(fā)生改變炸枣,所有依賴對象(觀察者對象)都得到通知,如果這樣的依賴關(guān)系很緊密弄唧,不能很好地抵御變化抛虏。

Class mainform:public forms{

? ? Textbox*txtfilepath;

? ? Texbox*txtfilenumber;

Public:

? ? Voidbutton_click(){

? ? Stringfilepath = txtfilepath->gettext();

? ? Intnumber = atoi(txtfilenumber->gettext().c_str());

? ? Filesplittersplitter(filepath, number);

? ? Splitter.split();

}

};

class filesplitter{

stringm_filepath;

intm_filenumber;

public:

filesplitter(conststring& filepath, int filenumber):

{}

void split(){

//讀取大文件

//分批次向小文件中寫入

for(int I = 0; i

//…

}

}

};

需求是提供一個進度條,來展示完成進度

首先在maiform上有一個progressbar* progressbar成員

在file_splitter里也放一個progressbar

依賴:A依賴B套才,A在編譯的時候只有B存在才能通過。

編譯是依賴慕淡,

當(dāng)我不需要用這個bar的時候會出問題背伴,這個progressbar其實是一個通知。通知可以用抽象的方式來表達峰髓,而不是用一個控件

class IProgress{

public:

virtualvoid DoProgress(float value) = 0;

virtual~IProgress()

};

所以在filesplitter里就變成了

IProgress* m_Iprogress//抽象通知機制

If(m_Iprogress != nullptr){

M_Iprogress->DoProgress(i+1)/m_filenumber;

}

然后mainform多重繼承Iprogress傻寂,C++一般用到多重繼承都是一個基類和接口

裝飾模式:

Decorator裝飾模式

“單一職責(zé)模式”在軟件組件設(shè)計中,如果責(zé)任劃分不清晰携兵,使用繼承得到的結(jié)果往往會讓子類急劇膨脹疾掰,同時充斥著重復(fù)代碼,這時候關(guān)鍵要劃清責(zé)任徐紧。

典型的模式有decorator和bridge静檬。

Class stream{

Public:

? ? Virtualchar Read(int number) = 0;

? ? Virtualvoid seek(int position) = 0;

? ? Virtualvoid write(char data) = 0;

? ? Virtual~Stream(){}

};

class filestream : public stream{

};

class Networkstream: public stream{

};

我們需要對流的主體進行曹組偶以后才能加密。

Class CtyptoFileStream : public FileStream{

Public:

? ? Virtualchar Read(int number){

? ? FileStream:read(number);//讀文件流

}

};

緩沖操作

//額外的加密操作

//額外的緩沖操作

這個設(shè)計的問題

最頂上是stream并级,被filestream, networkstream和memeorystream三種繼承拂檩,然后每個分別有加密和緩沖的流

這樣流就有很多,但其中有重復(fù)的代碼

如何重構(gòu)嘲碧?

取消繼承稻励,把父類當(dāng)做一個對象放入類中

然后再把各個父類做成多態(tài),用基類來表示愈涩,會發(fā)現(xiàn)所有的類全都一樣望抽,只是運行的時候new出來的對象不一樣加矛。

但是要保證流的方法是虛方法,所以要繼承自基類stream

橋模式:

由于某些類型的固有實現(xiàn)邏輯煤篙,使得他們有多個變化的維度

class messager(

public:

virtualvoid login

virtualvoid sendmessage

virtualvoid sendpicture

virtualvoid playsound

virtualvoid drawshape

virtualvoid writetext

virtual~message

);

我們還要支持PC平臺和mobile平臺的設(shè)計

class PCMessagerBase: public Messager{

public:

//重寫后面的幾個方法

};

class MobileMessagerBase: public Messager{

};

我們會發(fā)現(xiàn)在不同的平臺上要支持不同的功能

class PCMessageLite: public PCmessagerBase{

};

class PCMessagerPerfect: publicPCMessagerBase{

};

class MobileMessagerLite: publicMobileMessagerBase{

};

后面的類可以用messager的多態(tài)來實現(xiàn)斟览,然后發(fā)現(xiàn)后面的lite和perfect并沒有重載前面的后面幾個方法,所以要把messager拆分開成兩個類舰蟆。趣惠。

和decorator方法很像

如果子類里有重復(fù)的字段,都要往上提

abstraction和implementor身害,在abstraction里有一個implementor的指針味悄,并且兩個東西分別有各自的子類,向兩個不同的方向延伸塌鸯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侍瑟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丙猬,更是在濱河造成了極大的恐慌涨颜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茧球,死亡現(xiàn)場離奇詭異庭瑰,居然都是意外死亡,警方通過查閱死者的電腦和手機抢埋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門弹灭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人揪垄,你說我怎么就攤上這事穷吮。” “怎么了饥努?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵捡鱼,是天一觀的道長。 經(jīng)常有香客問我酷愧,道長驾诈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任溶浴,我火速辦了婚禮翘鸭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘戳葵。我一直安慰自己就乓,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著生蚁,像睡著了一般噩翠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邦投,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天伤锚,我揣著相機與錄音,去河邊找鬼志衣。 笑死屯援,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的念脯。 我是一名探鬼主播狞洋,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绿店!你這毒婦竟也來了吉懊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤假勿,失蹤者是張志新(化名)和其女友劉穎借嗽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體转培,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡恶导,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了浸须。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惨寿。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖羽戒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虎韵,我是刑警寧澤易稠,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站包蓝,受9級特大地震影響驶社,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜测萎,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一亡电、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧硅瞧,春花似錦份乒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瘾英。三九已至,卻和暖如春颂暇,著一層夾襖步出監(jiān)牢的瞬間缺谴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工耳鸯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留湿蛔,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓县爬,卻偏偏與公主長得像阳啥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捌省,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容