|
每一個模式描述了一個在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的解決方案的核心
——Christopher Alexander
設(shè)計模式描述了軟件設(shè)計過程中某一類常見問題的一般性的解決方案。面向?qū)ο笤O(shè)計模式描述了面向?qū)ο笤O(shè)計過程中、特定場景下、類與相互通信的對象之間常見的組織關(guān)系。人是一個經(jīng)驗(yàn)性的動物
GoF 23種設(shè)計模式
歷史性著作《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書中描述了23種經(jīng)典面向?qū)ο笤O(shè)計模式,創(chuàng)立了模式在軟件設(shè)計中的地位。該書四位作者被人們并成為Gang of Four(GoF),“四人組”,該書描述的23種經(jīng)典設(shè)計模式又被人們稱為GoF23種設(shè)計模式。
由于《設(shè)計模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》一書確定了設(shè)計模式的地位,人們通常所說的設(shè)計模式隱含地表示“面向?qū)ο笤O(shè)計模式”。但這并不意味“設(shè)計模式”就等于“面向?qū)ο笤O(shè)計模式”。除了“面向?qū)ο笤O(shè)計模式”外,還有其他設(shè)計模式。除了GoF23中設(shè)計模式外,還有更多的面向?qū)ο笤O(shè)計模式。
GoF23種設(shè)計模式是學(xué)習(xí)面向?qū)ο笤O(shè)計模式的起點(diǎn),而非終點(diǎn);本課程的目標(biāo)是讓大家在建立在有效方法的基礎(chǔ)上,掌握GoF23種設(shè)計模式。
設(shè)計模式與面向?qū)ο?/strong>
面向?qū)ο笤O(shè)計模式解決的是“類與相互通信的對象之間的組織關(guān)系”,包括它們的角色、職責(zé)、協(xié)作方式幾個方面。面向?qū)ο笤O(shè)計模式是“好的面向?qū)ο笤O(shè)計”,所謂“好的面向?qū)ο笤O(shè)計”是那些可以滿足“應(yīng)對變化,提高服用”的設(shè)計。面向?qū)ο笤O(shè)計模式描述的是軟件設(shè)計,因此它是獨(dú)立于編程語言的,但是面向?qū)ο笤O(shè)計模式的最終實(shí)現(xiàn)仍然要使用面向?qū)ο缶幊陶Z言來表達(dá),本課程基于C#語言,但實(shí)際上它適用于支持.NET框架的所有.NET語言,如Visual Basic.NET、C++/CLI等。
面向?qū)ο笤O(shè)計模式不像算法技巧,可以照搬照用,它是建立在對“面向?qū)ο?rdquo;純熟、深入的理解的基礎(chǔ)上的經(jīng)驗(yàn)性知識。掌握面向?qū)ο笤O(shè)計模式的前提是首先掌握“面向?qū)ο?rdquo;!
從編程語言直觀了解面向?qū)ο?/strong>
各種面向?qū)ο缶幊陶Z言相互有別,但都能看到它們對面向?qū)ο笕髾C(jī)制的支持,即:“封裝、繼承、多態(tài)”
-封裝,隱藏內(nèi)部實(shí)現(xiàn)
-繼承,復(fù)用現(xiàn)有代碼
-多態(tài),改寫對象行為
使用面向?qū)ο缶幊陶Z言(如C#),可以推動程序員以面向?qū)ο蟮乃季S來思考軟件設(shè)計結(jié)構(gòu),從而強(qiáng)化面向?qū)ο蟮木幊谭妒健#是一門支持面向?qū)ο缶幊痰膬?yōu)秀語言,包括:各種級別的封裝支持;單實(shí)現(xiàn)繼承+多接口實(shí)現(xiàn);抽象方法與虛方法重寫。
但OOPL并非面向?qū)ο蟮娜?/strong>
通過面向?qū)ο缶幊陶Z言(OOPL)認(rèn)識到的面向?qū)ο螅⒉皇敲嫦驅(qū)ο蟮娜浚踔林皇菧\陋的面向?qū)ο蟆OPL的三大機(jī)制“封裝、繼承、多態(tài)”可以表達(dá)面向?qū)ο蟮乃懈拍睿@三大機(jī)制本身并沒有刻畫出面向?qū)ο蟮暮诵木瘛Q言之,既可以用這三大機(jī)制做出“好的面向?qū)ο笤O(shè)計”,也可以用這三大機(jī)制做出“差的面向?qū)ο笤O(shè)計”。不是使用了面向?qū)ο蟮恼Z言(例如C#),就實(shí)現(xiàn)了面向?qū)ο蟮脑O(shè)計與開發(fā)!因此我們不能依賴編程語言的面向?qū)ο髾C(jī)制,來掌握面向?qū)ο蟆?/p>
OOPL沒有回答面向?qū)ο蟮母拘詥栴}——我們?yōu)槭裁匆褂妹嫦驅(qū)ο螅课覀儜?yīng)該怎樣使用三大機(jī)制來實(shí)現(xiàn)“好的面向?qū)ο?rdquo;?我們應(yīng)該遵循什么樣的面向?qū)ο笤瓌t?任何一個嚴(yán)肅的面向?qū)ο蟪绦騿T(例如C#程序員),都需要系統(tǒng)地學(xué)習(xí)面向?qū)ο蟮闹R,單純從編程語言上獲得的面向?qū)ο笾R,不能夠勝任面向?qū)ο笤O(shè)計與開發(fā)。
從一個示例談起
重新認(rèn)識面向?qū)ο?/strong>
對于前面的例子,從宏觀層面來看,面向?qū)ο蟮臉?gòu)建方式更能適應(yīng)軟件的變化,能將變化所帶來的影響減為最小。從微觀層面來看,面向?qū)ο蟮姆绞礁鼜?qiáng)調(diào)各個類的“責(zé)任”,新增員工類型不會影響原來員工類型的實(shí)現(xiàn)代碼——這更符合真實(shí)的世界,也更能控制變化所影響的范圍,畢竟Engineer類不應(yīng)該為新增的“鐘點(diǎn)工”來買單……
對象是什么?
-從概念層面講,對象是某種擁有責(zé)任的抽象。
-從規(guī)格層面講,對象是一系列可以被其他對象使用的公共接口。
-從語言實(shí)現(xiàn)層面來看,對象封裝了代碼和數(shù)據(jù)。
有了這些認(rèn)識之后,怎樣才能設(shè)計“好的面向?qū)ο?rdquo;?
-遵循一定的面向?qū)ο笤O(shè)計原則
-熟悉一些典型的面向?qū)ο笤O(shè)計模式
從設(shè)計原則到設(shè)計模式
針對接口編程,而不是針對實(shí)現(xiàn)編程:客戶無需知道所使用對象的特定類型,只需要知道對象擁有客戶所期望的接口
優(yōu)先使用對象組合,而不是類繼承:類繼承通常為“白箱復(fù)用”,對象組合通常為“黑箱復(fù)用”。繼承在某種成都上破壞了封裝性,子類父類耦合度高;而對象組合則只要求被組合的對象具有良好定義的接口,耦合度低。
封裝變化點(diǎn)
-使用封裝來創(chuàng)建對象之間的分界層,讓設(shè)計者可以在分界層的一側(cè)進(jìn)行修改,而不會對另一側(cè)產(chǎn)生不良的影響,從而實(shí)現(xiàn)層次間的松耦合。使用重構(gòu)得到模式——設(shè)計模式的應(yīng)用不宜先入為主,一上來就使用設(shè)計模式是對設(shè)計模式的最大誤用。沒有一步到位的設(shè)計模式。敏捷軟件開發(fā)實(shí)踐提倡的“Refactoring to Patterns”是目前普遍公認(rèn)的最好的使用設(shè)計模式的方法。
幾條更具體的設(shè)計原則
單一職責(zé)原則(SRP)
-一個類應(yīng)該僅有一個引起它變化的原因。
開放封閉原則(OCP)
-類模塊應(yīng)該是可擴(kuò)展的,但是不可修改(對擴(kuò)展開放,對更改封閉)
Liskov替換原則(LSP)
-子類必須能夠替換它們的基類
依賴倒置原則(DIP)
-高層模塊不應(yīng)該依賴于低層模塊,二者都應(yīng)該依賴于抽象。
-抽象不應(yīng)該依賴于實(shí)現(xiàn)細(xì)節(jié),實(shí)現(xiàn)細(xì)節(jié)應(yīng)該依賴于抽象。
接口隔離原則(ISP)
-不應(yīng)該強(qiáng)迫客戶程序依賴于它們不用的方法。
總結(jié)
設(shè)計模式描述了軟件設(shè)計過程中某一類常見問題的一般性的解決方案。面向?qū)ο笤O(shè)計模式描述了面向?qū)ο笤O(shè)計過程中、特定場景下、類與相互通信的對象之間常見的組織關(guān)系。深刻理解面向?qū)ο笫菍W(xué)好設(shè)計模式的基礎(chǔ),掌握一定的面向?qū)ο笤O(shè)計原則才能把握面向?qū)ο笤O(shè)計模式的精髓,從而實(shí)現(xiàn)靈活運(yùn)用設(shè)計模式。
三大基本面向?qū)ο笤O(shè)計原則
-針對接口編程,而不是針對實(shí)現(xiàn)編程
-優(yōu)先使用對象組合,而不是類繼承
-封裝變化點(diǎn)
使用重構(gòu)得到模式。敏捷軟件開發(fā)實(shí)踐提倡的“Refactoring to Patterns”是目前普遍公認(rèn)的最好的使用設(shè)計模式的方法。
it知識庫:C#面向?qū)ο笤O(shè)計模式縱橫談:面向?qū)ο笤O(shè)計模式與原則,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。