C++設(shè)計(jì)模式是本周開(kāi)始的一門(mén)全新的課程色罚,在完成了第一周的學(xué)習(xí)之后碰缔,對(duì)C++設(shè)計(jì)模式有了一定的認(rèn)識(shí)和了解,因此有一些總結(jié)和心得在這里通過(guò)學(xué)習(xí)筆記的方式分享出來(lái)戳护,筆記我是跟著老師在視頻中所講的內(nèi)容按照順序記錄的金抡,也不能說(shuō)是流水賬瀑焦,對(duì)課程中的一些問(wèn)題還是添加了自己的理解和分析,供也在學(xué)習(xí)C++的小伙伴用作學(xué)習(xí)交流梗肝,如有理解不到位的地方榛瓮,歡迎批評(píng)指正。
在正式開(kāi)始學(xué)習(xí)之前巫击,首先明確本課程的目標(biāo):
1.理解松耦合設(shè)計(jì)思想
2.掌握面向?qū)ο笤O(shè)計(jì)原則
3.掌握重構(gòu)技法改善設(shè)計(jì)
4.掌握GOF核心設(shè)計(jì)模式
一開(kāi)始看到課程目標(biāo)我也是云里霧里的禀晓,但是相信在今后幾周的學(xué)習(xí)中,我們肯定能達(dá)到這個(gè)學(xué)習(xí)目標(biāo)坝锰!
一.設(shè)計(jì)模式簡(jiǎn)介
什么是設(shè)計(jì)模式呢粹懒?“每一個(gè)模式描述了一個(gè)在我們周?chē)粩嘀貜?fù)發(fā)生的問(wèn)題,以及該問(wèn)題的解決方案核心顷级。這樣凫乖,你就能一次又一次地使用該方案而不必做重復(fù)勞動(dòng)」保”而我們就是要以面向?qū)ο鬄榛A(chǔ)帽芽,主要學(xué)習(xí)掌握“好的面向?qū)ο笤O(shè)計(jì)”。因此我們必須將向下的底層思維和向上的抽象思維聯(lián)系起來(lái)翔冀,把握機(jī)器底層從微觀理解對(duì)象構(gòu)造导街,將我們周?chē)澜绯橄鬄槌绦虼a。向下深入理解三大面向?qū)ο髾C(jī)制:封裝(隱藏內(nèi)部實(shí)現(xiàn))纤子、繼承(復(fù)用現(xiàn)有代碼)搬瑰、多態(tài)(改寫(xiě)對(duì)象行為);向上深刻把握面向?qū)ο髾C(jī)制所帶來(lái)的抽象意義计福,掌握什么是“好的面向?qū)ο笤O(shè)計(jì)”跌捆。
軟件設(shè)計(jì)有其固有的復(fù)雜性,軟件設(shè)計(jì)復(fù)雜的根本原因在于“變化”象颖,客戶(hù)需求的變化佩厚、技術(shù)平臺(tái)的變化、開(kāi)發(fā)團(tuán)隊(duì)的變化说订、市場(chǎng)環(huán)境的變化… …通常抄瓦,人們解決復(fù)雜性會(huì)用到兩種方法:一種是分解。這很好理解陶冷,將一個(gè)復(fù)雜的問(wèn)題拆分成幾個(gè)簡(jiǎn)單的問(wèn)題钙姊,但是這種方法的缺點(diǎn)在于不是任何問(wèn)題都適用且復(fù)用性差。第二種是抽象埂伦。由于不能掌握全部的復(fù)雜對(duì)象煞额,我們選擇忽視它的非本質(zhì)細(xì)節(jié),而去處理泛化和理想化了的對(duì)象模型。一個(gè)好的設(shè)計(jì)軟件膊毁,一定是能夠復(fù)用的胀莹!變化是復(fù)用的天敵,面向?qū)ο笤O(shè)計(jì)最大的優(yōu)勢(shì)在于抵御變化婚温!
二.面向?qū)ο笤O(shè)計(jì)原則(八大原則)
1.依賴(lài)倒置原則(DIP)
高層模塊(穩(wěn)定)不應(yīng)該依賴(lài)于低層模塊(變化)描焰,二者都應(yīng)該依賴(lài)于抽象(穩(wěn)定)。
抽象(穩(wěn)定)不應(yīng)該依賴(lài)于實(shí)現(xiàn)細(xì)節(jié)(變化)栅螟,實(shí)現(xiàn)細(xì)節(jié)應(yīng)該依賴(lài)于抽象(穩(wěn)定)荆秦。
2.開(kāi)放封閉原則(OCP)
對(duì)擴(kuò)展開(kāi)放,對(duì)更改封閉力图。
類(lèi)模塊應(yīng)該是可擴(kuò)展的步绸,但是不可修改。
3.單一職責(zé)原則(SRP)
一個(gè)類(lèi)應(yīng)該僅有一個(gè)引起它變化的原因吃媒。
變化的方向隱含著類(lèi)的責(zé)任靡努。
4.Liskov替換原則(LSP)
子類(lèi)必須能夠替換它們的基類(lèi)(IS-A)。
繼承表達(dá)類(lèi)型抽象晓折。
5.接口隔離原則(ISP)
不應(yīng)該強(qiáng)迫客戶(hù)程序依賴(lài)它們不用的方法。
接口應(yīng)該小而完備兽泄。
6.優(yōu)先使用對(duì)象組合漓概,而不是類(lèi)繼承
類(lèi)繼承通常為“白箱復(fù)用”,對(duì)象組合通常為“黑箱復(fù)用”病梢。
繼承在某種程度上破壞了封裝性胃珍,子類(lèi)父類(lèi)耦合度高。
而對(duì)象組合則只要求被組合的對(duì)象具有良好定義的接口蜓陌,耦合度低觅彰。
7.封裝變化點(diǎn)
使用封裝來(lái)創(chuàng)建對(duì)象之間的分界層,讓設(shè)計(jì)者可以在分界層的一側(cè)進(jìn)行修改钮热,而不會(huì)對(duì)另一側(cè)產(chǎn)生不良影響填抬,從而實(shí)現(xiàn)層次間的松耦合。
8.針對(duì)接口編程隧期,而不是針對(duì)實(shí)現(xiàn)編程
不將變量類(lèi)型聲明為某個(gè)特定的具體類(lèi)飒责,而是聲明為某個(gè)接口。
客戶(hù)程序無(wú)需獲知對(duì)象的具體類(lèi)型仆潮,只需要知道對(duì)象所具有的接口宏蛉。
減少系統(tǒng)中各部分的依賴(lài)關(guān)系,從而實(shí)現(xiàn)“高內(nèi)聚性置、松耦合”的類(lèi)型設(shè)計(jì)方案拾并。
三.GOF-23種設(shè)計(jì)模式分類(lèi)
1.從目的來(lái)看分為:
創(chuàng)建型(Creational)模式:將對(duì)象的部分創(chuàng)建工作延遲到子類(lèi)或者其他對(duì)象,從而應(yīng)對(duì)需求變化為對(duì)象創(chuàng)建時(shí)具體類(lèi)型實(shí)現(xiàn)引來(lái)的沖擊。
結(jié)構(gòu)型(Structural)模式:通過(guò)類(lèi)繼承或者對(duì)象組合獲得更靈活的結(jié)構(gòu)嗅义,從而應(yīng)對(duì)需求變化為對(duì)象的結(jié)構(gòu)帶來(lái)的沖擊屏歹。
行為型(Behavioral)模式:通過(guò)類(lèi)繼承或者對(duì)象組合來(lái)劃分類(lèi)與對(duì)象間的職責(zé),從而應(yīng)對(duì)需求變化為多個(gè)交互的對(duì)象帶來(lái)的沖擊芥喇。
2.從范圍(實(shí)現(xiàn)手段)來(lái)看分為:
類(lèi)模式處理類(lèi)與子類(lèi)的靜態(tài)關(guān)系西采。
對(duì)象模式處理對(duì)象間的動(dòng)態(tài)關(guān)系。
3.從封裝變化角度來(lái)看分為:
4.重構(gòu)獲得模式(Refactoring to Patterns)
重構(gòu)關(guān)鍵技法:
靜態(tài)->動(dòng)態(tài)
早綁定->晚綁定
繼承->組合
編譯時(shí)依賴(lài)->運(yùn)行時(shí)依賴(lài)
緊耦合->松耦合
5.“組件協(xié)作”模式
現(xiàn)代軟件專(zhuān)業(yè)分工之后的第一個(gè)結(jié)果是“框架與應(yīng)用程序的劃分”继控,“組件協(xié)作”模式通過(guò)晚期綁定械馆,來(lái)實(shí)現(xiàn)框架與應(yīng)用程序之間的松耦合,是二者之間協(xié)作時(shí)常用的模式武通。
典型模式:
Template Method
Strategy
Observer/Event
A.Template Method模式
動(dòng)機(jī)(Motivation):
在軟件構(gòu)建過(guò)程中霹崎,對(duì)于某一項(xiàng)任務(wù),它常常有穩(wěn)定的整體操作結(jié)構(gòu)冶忱,但各個(gè)子步驟卻有很多改變的需求尾菇,或者由于固有的原因(比如框架與應(yīng)用之間的關(guān)系)而無(wú)法和任務(wù)的整體結(jié)構(gòu)同時(shí)實(shí)現(xiàn)。
如何在確定穩(wěn)定操作結(jié)構(gòu)的前提下囚枪,來(lái)靈活應(yīng)對(duì)各個(gè)子步驟的變化或者晚期實(shí)現(xiàn)需求派诬?
模式定義:
定義一個(gè)操作中的算法的骨架(穩(wěn)定),而將一些步驟延遲(變化)到子類(lèi)中链沼。Template
Method使得子類(lèi)可以不改變(復(fù)用)一個(gè)算法的結(jié)構(gòu)即可重定義(override重寫(xiě))該算法的某些特定步驟默赂。
結(jié)構(gòu)(Structure):
要點(diǎn)總結(jié):
Template Method模式是一種非常基礎(chǔ)性的設(shè)計(jì)模式括勺,在面向?qū)ο笙到y(tǒng)中有著大量的應(yīng)用缆八。它用最簡(jiǎn)潔的機(jī)制(虛函數(shù)的多態(tài)性)為很多應(yīng)用程序框架提供了靈活的擴(kuò)展點(diǎn),是代碼復(fù)用方面的基本實(shí)現(xiàn)結(jié)構(gòu)疾捍。
除了可以靈活應(yīng)對(duì)子步驟的變化外奈辰,“不要調(diào)用我,讓我來(lái)調(diào)用你”的反向控制結(jié)構(gòu)是Template Method的典型應(yīng)用乱豆。
在具體實(shí)現(xiàn)方面奖恰,被Template Method調(diào)用的虛方法可以具有實(shí)現(xiàn),也可以沒(méi)有任何實(shí)現(xiàn)(抽象方法咙鞍、純虛方法)房官,但一般推薦將它們?cè)O(shè)置為protected方法。
B.Strategy策略模式
動(dòng)機(jī)(Motivation):
在軟件構(gòu)建過(guò)程中续滋,某些對(duì)象使用的算法可能多種多樣翰守,經(jīng)常改變,如果將這些算法都編碼到對(duì)象中疲酌,將會(huì)使對(duì)象變得異常復(fù)雜蜡峰;而且有時(shí)候支持不使用的算法也是一個(gè)性能負(fù)擔(dān)了袁。
如何在運(yùn)行時(shí)根據(jù)需要透明地改變對(duì)象的算法?將算法與對(duì)象本身解耦湿颅,從而避免上述問(wèn)題载绿?
模式定義:
定義一系列算法,把它們一個(gè)個(gè)封裝起來(lái)油航,并且使它們可互相替換(變化)崭庸。該模式使得算法可獨(dú)立于使用它的客戶(hù)程序(穩(wěn)定)而變化(擴(kuò)展,子類(lèi)化)谊囚。
結(jié)構(gòu)(Structure)
要點(diǎn)總結(jié):
Strategy及其子類(lèi)為組件提供了一系列可重用的算法怕享,從而可以使得類(lèi)型在運(yùn)行時(shí)方便地根據(jù)需要在各個(gè)算法之間切換。
Strategy模式提供了用條件判斷語(yǔ)句以外的另一種選擇镰踏,消除條件判斷語(yǔ)句函筋,就是在解耦合。含有許多條件判斷語(yǔ)句的代碼通常都需要Strategy模式奠伪。
如果Strategy對(duì)象沒(méi)有實(shí)例變量跌帐,那么各個(gè)上下文可以共享同一個(gè)Strategy對(duì)象,從而節(jié)省對(duì)象開(kāi)銷(xiāo)绊率。
C.Observer觀察者模式
動(dòng)機(jī)(Motivation):
在軟件構(gòu)建過(guò)程中谨敛,我們需要為某些對(duì)象建立一種“通知依賴(lài)關(guān)系”--一個(gè)對(duì)象(目標(biāo)對(duì)象)的狀態(tài)發(fā)送改變,所有的依賴(lài)對(duì)象(觀察者對(duì)象)都將得到通知滤否。如果這樣的依賴(lài)關(guān)系過(guò)于緊密佣盒,將使軟件不能很好地抵御變化。
使用面向?qū)ο蠹夹g(shù)顽聂,可以將這種依賴(lài)關(guān)系弱化,并形成一種穩(wěn)定的依賴(lài)關(guān)系盯仪。從而實(shí)現(xiàn)軟件體系結(jié)構(gòu)的松耦合紊搪。
模式定義:
定義對(duì)象間的一種一對(duì)多(變化)的依賴(lài)關(guān)系,以便當(dāng)一個(gè)對(duì)象(Subject)的狀態(tài)發(fā)生改變時(shí)全景,所有依賴(lài)于它的對(duì)象都得到通知并自動(dòng)更新浑塞。
結(jié)構(gòu)(Structure):
要點(diǎn)總結(jié):
使用面向?qū)ο蟮某橄蟀渚琌bserver模式使得我們可以獨(dú)立地改變目標(biāo)與觀察者,從而使二者之間的依賴(lài)關(guān)系達(dá)到松耦合。
目標(biāo)發(fā)送通知時(shí)罪既,無(wú)需指定觀察者,通知(可以攜帶通知信息作為參數(shù))會(huì)自動(dòng)傳播于置。
觀察者自己決定是否需要訂閱通知劣光,目標(biāo)對(duì)象對(duì)此一無(wú)所知。
Observer模式是基于事件的UI框架中非常常用的設(shè)計(jì)模式称开,也是MVC模式的一個(gè)重要組成部分亩钟。
6.“單一職責(zé)”模式
在軟件組件的設(shè)計(jì)中乓梨,如果責(zé)任劃分的不清晰,使用繼承得到的結(jié)果往往是隨著需求的變化清酥,子類(lèi)急劇膨脹扶镀,同時(shí)充斥著重復(fù)代碼,這時(shí)候的關(guān)鍵是劃清責(zé)任焰轻。
典型模式:
Decorator
Bridge
D.Decorator裝飾模式
動(dòng)機(jī)(Motivation)
在某些情況下我們可能會(huì)“過(guò)度地使用繼承來(lái)擴(kuò)展對(duì)象的功能”臭觉,由于繼承為類(lèi)型引入的靜態(tài)特質(zhì),使得這種擴(kuò)展方式缺乏靈活性辱志;并且隨著子類(lèi)的增多(擴(kuò)展功能的增多)蝠筑,各種子類(lèi)的組合(擴(kuò)展功能的組合)會(huì)導(dǎo)致更多子類(lèi)的膨脹。
如何使“對(duì)象功能的擴(kuò)展”能夠根據(jù)需要來(lái)動(dòng)態(tài)地實(shí)現(xiàn)荸频?同時(shí)避免“擴(kuò)展功能的增多”帶來(lái)的子類(lèi)膨脹的問(wèn)題菱肖?從而使得任何“功能擴(kuò)展變化”所導(dǎo)致的影響為最低?
模式定義:
動(dòng)態(tài)(組合)地給一個(gè)對(duì)象增加一些額外的職責(zé)旭从。就增加功能而言稳强,decorator模式比生成子類(lèi)(繼承)更為靈活(消除重復(fù)代碼&減少子類(lèi)個(gè)數(shù))。
結(jié)構(gòu)(Structure):
要點(diǎn)總結(jié):
通過(guò)采用組合而非繼承的手法和悦,Decorator模式實(shí)現(xiàn)了在運(yùn)行時(shí)動(dòng)態(tài)擴(kuò)展對(duì)象功能的能力退疫,而且可以根據(jù)需要擴(kuò)展多個(gè)功能。避免了使用繼承帶來(lái)的“靈活性差”和“多子類(lèi)衍生問(wèn)題”鸽素。
Decorator類(lèi)在接口上表現(xiàn)為is-a
Component的繼承關(guān)系褒繁,即Decorator類(lèi)繼承了Component類(lèi)所具有的接口。但實(shí)現(xiàn)上又表現(xiàn)為has-a Component的組合關(guān)系馍忽,即Decorator類(lèi)又使用了另外一個(gè)Component類(lèi)棒坏。
Decorator模式的目的并非解決“多子類(lèi)衍生的多繼承”問(wèn)題,Decorator模式應(yīng)用的要點(diǎn)在于解決“主體類(lèi)在多個(gè)方向上的擴(kuò)展功能”——是為“裝飾”的含義遭笋。
E.Bridge橋模式
動(dòng)機(jī)(Motivation):
由于某些類(lèi)型的固有的實(shí)現(xiàn)邏輯坝冕,使得它們具有兩個(gè)變化的維度,乃至多個(gè)緯度的變化瓦呼。
如何應(yīng)對(duì)這種“多維度的變化”喂窟?如何利用面向?qū)ο蠹夹g(shù)來(lái)使得類(lèi)型可以輕松地沿著兩個(gè)乃至多個(gè)方向的變化,而不引入額外的復(fù)雜度央串?
模式定義:
將抽象部分(業(yè)務(wù)功能)與實(shí)現(xiàn)部分(平臺(tái)實(shí)現(xiàn))分離磨澡,使它們都可以獨(dú)立地變化。
結(jié)構(gòu)(Structure):
要點(diǎn)總結(jié):
Bridge模式使用“對(duì)象間的組合關(guān)系”解耦了抽象和實(shí)現(xiàn)之間固有的綁定關(guān)系质和,使得抽象和實(shí)現(xiàn)可以沿著各自的緯度來(lái)變化稳摄。所謂抽象和實(shí)現(xiàn)沿著各自緯度的變化,即“子類(lèi)化”它們饲宿。
Bridge模式有時(shí)候類(lèi)似于多繼承方案秩命,但是多繼承方案往往違背單一職責(zé)原則(即一個(gè)類(lèi)只有一個(gè)變化的原因)尉共,復(fù)用性比較差。Bridge模式是比多繼承方案更好的解決方法弃锐。
Bridge模式的應(yīng)用一般在“兩個(gè)非常強(qiáng)的變化緯度”袄友,有時(shí)一個(gè)類(lèi)也有多于兩個(gè)的變化維度,這時(shí)可以使用Bridge的擴(kuò)展模式霹菊。