GeekBand C++ Week9 Notes

C++設計模式

為了理解松耦合設計思想,掌握面向對象設計原則

什么是設計模式?

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

設計模式不等于面向對象設計模式

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

語言構造,變易轉換

內存模型

運行時機制

抽象思維:向上,如何將我們的現實世界抽象為程序代碼,

面向對象

組件封裝

設計模式

架構模式

深入理解面向對象:

向下:封裝,繼承,多態

向上:深刻把握面向對象機制所帶來的抽象意義,理解如何利用這些機制來表達現實世界,掌握什么是好的面向對象設計

如何解決復雜性?

分解,人們面對復雜性有一個常見的做法:分而治之,將大問題分解為多個小問題,將復雜問題分解為多個簡單問題

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

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,一個形狀負責畫自己,實現自己的draw.

在子類中overide自己父類的虛函數

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;//多態

public:

}

在后面對shapevector中的元素進行多態調用。

兩種方法的區別,哪種更好?

客戶需求的變化:

如果客戶需要多加一個圓

//增加一個類

class Circle{

};

在mainform里增加一個

vector CircleVector

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

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

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

class Circle: public shape{

public:

//負責自己的draw

}

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

全都不用改變除了刷新

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

重用性得到了很高的提升

當需求變化的時候,更加方便

DRY!!!

由于不能掌握全部的復雜對象,處理泛化的問題

面向對象的設計原則

變化是復用的天敵,面向對象設計最大的優勢在于抵御變化。

理解隔離變化

從宏觀層面來看,面向對象的構建方式更能適應軟件的變化,能將變化所帶來的影響減為最小。

各司其職

從微觀層面來看,面向對象的方式更強調個各類的責任

在第一個例子里,畫線的責任從mainform到了形狀自己,接口一樣但實際不一樣。

對象是什么?

從語言實現層面來看,對象封裝了代碼和數據,

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

從概念層面來看,

面向對象的設計原則//設計原則比模式更重要

依賴倒置原則(DIP)

高層模塊(穩定)不應該依賴于低層模塊(變化),二者都應該依賴于抽象(穩定)

抽象(穩定)不應該依賴于實現細節(變化),實現細節應該依賴于抽象(穩定)。

開放封閉原則(OCP)

對擴展開放,對更改封閉

類模塊應該是可擴展的,但是不可以修改

單一職責原則(SRP)

一個類應該僅有一個引起它變化的原因

變化的方向隱含著類的責任

Liskov替換原則(LSP)

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

繼承表達類型抽象

接口隔離原則(ISP)

不應該強迫客戶程序依賴它們不用的方法

接口應該小而完備

優先使用對象組合,而不是類繼承

類繼承通常為白箱復用,對象組合通常為黑箱復用。

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

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

封裝變化點

使用封裝來創建對象之間的分界層,讓設計者可以在分界層的一側進行修改,而不會對另一側產生不良影響。

針對接口編程,而不是針對實現編程。

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

減少系統中各部分的依賴關系,從而實現“高內聚,低耦合”類型的設計方案。

產業強盛的標志:接口標準化

模板方法

Template Method

GOF-23模式分類

設計模式的應用不應該先入為主,一上來就使用設計模式是對設計模式最大的誤用,沒有一步到位的設計模式。

重構的關鍵技法:

靜態到動態,早綁定到晚綁定,繼承到組合,編譯時依賴到運行時依賴,緊耦合到松耦合

組件協作模式:

框架與應用程序的劃分,組合協作模式通過晚期綁定,來實現框架和應用程序之間的松耦合,是二者之間協作時常用的模式。

典型模式:

template method

strategy

observer/event

動機:在軟件構件過程中,某項任務常常有穩定的整體操作結構,但各個子步驟卻有很多改變的需求,或者由于固有的原因,比如框架和應用之間的關系,而無法和任務的整體機構同時實現

class library{

public:

? ? voidstep1(){?

? ? //…

? ? }

? ? voidstep3(){

? ? //…

? ? }

? ? void step5(){

? ? }

};//程序庫開發人員

class Application{

? ? voidstep2{

? ? }

? ? void step4{

? ? }

};

int main(){

? ? Librarylib();

? ? Applicationapp();

? ? Lib.step1(); ??

? ? If(app.step2()){

? ? ? ? Lib.step3();

? ? }

….

}

另外一種做法:

庫的開發人員

除了1,3,5,也寫step2和step4

virtualbool step2(){}

virtualvoid step4(){}

把run()寫在類里,1,3,5是protected,虛的析構函數。

子類重寫實現

library* pLIb = new Apllication();

plib->run();

delete plib;

前一種方法lib開發人員開發1,3,5三個步驟,app開發人員開發2,4兩個步驟,和程序主流程

另一種lib開發人員寫1,3,5三個步驟和程序主流程,app開發人員開發2,4兩個步驟。

第一種是app調用lib的,第二種是lib的調用app的

第一種寫法是一種早綁定的寫法,因為lib一般寫的早,程序庫寫的早。晚的東西調用早的東西,但在面向對象語言中,有晚綁定的機制,lib寫的早但是它調用app,所以是晚綁定。模式定義一個操作算法的骨架(穩定),而將一些步驟延遲到子類中,template method是的子類可以不改變一個算法結構即可以重定義override,重寫該算法的某些特定步驟。

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

穩定中有變化,2,4支持變化,是虛函數的多態調用

c++中穩定的要寫成非虛函數,變化的要寫成虛函數

設計模式的假定條件是必須有一個穩定點

也一定有變化,設計模式的最大的作用就是在穩定和變化之間尋找一個平衡點,把兔子關進籠子里。

在具體實現方面,被template method調用的虛方法可以具有實現,也可以沒有任何實現(抽象方法,虛方法),但一般推薦把它們設置為protected方法。

“不要調用我,讓我來調用你”的反向控制結構。

策略模式:

strategy策略模式是一個組件協作類的模式,實現框架和應用程序之間的松耦合

動機:在軟件構件過程中,有些對象使用的算法可能多種多樣經常改變,如果將這些算法都編碼到對象中,將會使對象變得復雜,有時候支持不適用的算法也是一個性能負擔,透明得更改,使算法和對象解耦。

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);//多態調用

}

};

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

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

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

如果Strategy對象沒有實例變量,各個上下文可以共享一個strategy變量,從而節省對象開銷。

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

Observer/event觀察者模式

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

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存在才能通過。

編譯是依賴,

當我不需要用這個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裝飾模式

“單一職責模式”在軟件組件設計中,如果責任劃分不清晰,使用繼承得到的結果往往會讓子類急劇膨脹,同時充斥著重復代碼,這時候關鍵要劃清責任。

典型的模式有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);//讀文件流

}

};

緩沖操作

//額外的加密操作

//額外的緩沖操作

這個設計的問題

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

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

如何重構?

取消繼承,把父類當做一個對象放入類中

然后再把各個父類做成多態,用基類來表示,會發現所有的類全都一樣,只是運行的時候new出來的對象不一樣。

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

橋模式:

由于某些類型的固有實現邏輯,使得他們有多個變化的維度

class messager(

public:

virtualvoid login

virtualvoid sendmessage

virtualvoid sendpicture

virtualvoid playsound

virtualvoid drawshape

virtualvoid writetext

virtual~message

);

我們還要支持PC平臺和mobile平臺的設計

class PCMessagerBase: public Messager{

public:

//重寫后面的幾個方法

};

class MobileMessagerBase: public Messager{

};

我們會發現在不同的平臺上要支持不同的功能

class PCMessageLite: public PCmessagerBase{

};

class PCMessagerPerfect: publicPCMessagerBase{

};

class MobileMessagerLite: publicMobileMessagerBase{

};

后面的類可以用messager的多態來實現,然后發現后面的lite和perfect并沒有重載前面的后面幾個方法,所以要把messager拆分開成兩個類。。

和decorator方法很像

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

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容