面向?qū)ο蟮脑O(shè)計原則-類設(shè)計原則資料_第1頁
面向?qū)ο蟮脑O(shè)計原則-類設(shè)計原則資料_第2頁
面向?qū)ο蟮脑O(shè)計原則-類設(shè)計原則資料_第3頁
面向?qū)ο蟮脑O(shè)計原則-類設(shè)計原則資料_第4頁
面向?qū)ο蟮脑O(shè)計原則-類設(shè)計原則資料_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、面向?qū)ο蟮脑O(shè)計原則類設(shè)計原則在面向?qū)ο笤O(shè)計中,如何通過很小的設(shè)計改變就可以應(yīng)對設(shè)計需求的變化,這是令設(shè)計者極為關(guān)注的問題。為此不少OO先驅(qū)提出了很多有關(guān)面向?qū)ο蟮脑O(shè)計原則用于指導(dǎo)OO的設(shè)計和開發(fā)。下面是幾條與類設(shè)計相關(guān)的設(shè)計原則。1. 開閉原則(the Open Closed Principle OCP)一個模塊在擴(kuò)展性方面應(yīng)該是開放的而在更改性方面應(yīng)該是封閉的。因此在進(jìn)行面向?qū)ο笤O(shè)計時要盡量考慮接口封裝機(jī)制、抽象機(jī)制和多態(tài)技術(shù)。該原則同樣適合于非面向?qū)ο笤O(shè)計的方法,是軟件工程 設(shè)計方法的重要原則之一。我們以收音機(jī)的例子為例,講述面向?qū)ο蟮拈_閉原則。我們收聽節(jié)目時需要打開收音機(jī)電源,對準(zhǔn)電臺頻

2、率和進(jìn)行音量調(diào)節(jié)。但是對于不同的收音機(jī),實(shí)現(xiàn)這三個步驟的細(xì)節(jié)往往有所不同。比如自動收縮電臺的收音機(jī)和按鈕式收縮在操作細(xì)節(jié)上并不相同。因此,我們不太可能針對每種不同類型的收音機(jī)通過一個收音機(jī)類來實(shí)現(xiàn)(通過重載)這些不同的操作方式。但是我們可以定義一個收音機(jī)接口,提供開機(jī)、關(guān)機(jī)、增加頻率、降低頻率、增加音量、降低音量六個抽象方法。不同的收音機(jī)繼承并實(shí)現(xiàn)這六個抽象方法。這樣新增收音機(jī)類型不會影響其它原有的收音機(jī)類型,收音機(jī)類型擴(kuò)展極為方便。此外,已存在的收音機(jī)類型在修改其操作方法時也不會影響到其它類型的收音機(jī)。圖1是一個應(yīng)用OCP生成的收音機(jī)類圖的例子:圖12. 替換原則 (the Liskov S

3、ubstitution Principle LSP)子類應(yīng)當(dāng)可以替換父類并出現(xiàn)在父類能夠出現(xiàn)的任何地方。這個原則是Liskov于1987年提出的設(shè)計原則。它同樣可以從Bertrand Meyer 的DBC (Design by Contract) 的概念推出。我們以學(xué)生為例,夜校生為學(xué)生的子類,因此在任何學(xué)生可以出現(xiàn)的地方,夜校生均可出現(xiàn)。這個例子有些牽強(qiáng),一個能夠反映這個原則的例子時圓和橢圓,圓是橢圓的一個特殊子類。因此任何出現(xiàn)橢圓的地方,圓均可以出現(xiàn)。但反過來就可能行不通。Liskov的相關(guān)圖示見圖2:Page 1圖2 Liskov 原則運(yùn)用替換原則時,我們盡量把B設(shè)計為抽象類或者接口,讓

4、C繼承B(接口B)并實(shí)現(xiàn)操作A和操作B,運(yùn)行時,C實(shí)例替換B,這樣我們即可進(jìn)行新類的擴(kuò)展(繼承類B或接口B),同時無須對A進(jìn)行修改。3. 依賴原則 (the Dependency Inversion Principle DIP)在進(jìn)行業(yè)務(wù)設(shè)計時,與特定業(yè)務(wù)有關(guān)的依賴關(guān)系應(yīng)該盡量依賴接口和抽象類,而不是依賴于具體類。具體類只負(fù)責(zé)相關(guān)業(yè)務(wù)的實(shí)現(xiàn),修改具體類不影響與特定業(yè)務(wù)有關(guān)的依賴關(guān)系。在結(jié)構(gòu)化設(shè)計中,我們可以看到底層的模塊是對高層抽象模塊的實(shí)現(xiàn)(高層抽象模塊通過調(diào)用底層模塊),這說明,抽象的模塊要依賴具體實(shí)現(xiàn)相關(guān)的模塊,底層模塊的具體實(shí)現(xiàn)發(fā)生變動時將會嚴(yán)重影響高層抽象的模塊,顯然這是結(jié)構(gòu)化方法的

5、一個"硬傷"。面向?qū)ο蠓椒ǖ囊蕾囮P(guān)系剛好相反,具體實(shí)現(xiàn)類依賴于抽象類和接口(見圖-3)。為此,我們在進(jìn)行業(yè)務(wù)設(shè)計時,應(yīng)盡量在接口或抽象類中定義業(yè)務(wù)方法的原型,并通過具體的實(shí)現(xiàn)類(子類)來實(shí)現(xiàn)該業(yè)務(wù)方法,業(yè)務(wù)方法內(nèi)容的修改將不會影響到運(yùn)行時業(yè)務(wù)方法的調(diào)用。圖3依賴原則圖示Page 24. 接口分離原則(the Interface Segregation Principle ISP)采用多個與特定客戶類有關(guān)的接口比采用一個通用的涵蓋多個業(yè)務(wù)方法的接口要好。ISP原則是另外一個支持諸如COM等組件化的使能技術(shù)。缺少ISP,組件、類的可用性和移植性將大打折扣。這個原則的本質(zhì)相當(dāng)簡單

6、。如果你擁有一個針對多個客戶的類,為每一個客戶創(chuàng)建特定業(yè)務(wù)接口,然后使該客戶類繼承多個特定業(yè)務(wù)接口將比直接加載客戶所需所有方法有效。圖4展示了一個擁有多個客戶的類。它通過一個巨大的接口來服務(wù)所有的客戶。只要針對客戶A的方法發(fā)生改變,客戶B和客戶C就會受到影響。因此可能需要進(jìn)行重新編譯和發(fā)布。這是一種不幸的做法。圖4 帶有集成接口的服務(wù)類我們再看圖-5中所展示的技術(shù)。每個特定客戶所需的方法被置于特定的接口中,這些接口被Service類所繼承并實(shí)現(xiàn)。如果針對客戶A的方法發(fā)生改變,客戶B和客戶C并不會受到任何影響,也不需要進(jìn)行再次編譯和重新發(fā)布。以上四個原則是面向?qū)ο笾谐3S玫降脑瓌t。此外,除上述四

7、原則外,還有一些常用的經(jīng)驗(yàn)諸如類結(jié)構(gòu)層次以三到四層為宜、類的職責(zé)明確化(一個類對應(yīng)一個具體職責(zé))等可供我Page 3們在進(jìn)行面向?qū)ο笤O(shè)計參考。但就上面的幾個原則看來,我們看到這些類在幾何分布上呈現(xiàn)樹型拓?fù)涞年P(guān)系,這是一種良好、開放式的線性關(guān)系、具有較低的設(shè)計復(fù)雜度。一般說來,在軟件設(shè)計中我們應(yīng)當(dāng)盡量避免出現(xiàn)帶有閉包、循環(huán)的設(shè)計關(guān)系,它們反映的是較大的耦合度和設(shè)計復(fù)雜化。面向?qū)ο笤O(shè)計原則面向?qū)ο笤O(shè)計原則面向?qū)ο笤O(shè)計的基石是“開閉”原則。正在裝載數(shù)據(jù)“開一閉”原則講的是:一個軟件實(shí)體應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉。這個規(guī)則說的是,在設(shè)計一個模塊的時候,應(yīng)當(dāng)使這個模塊可以在不被修改的前提下被擴(kuò)展。從另外

8、一個角度講,就是所謂的“對可變性封裝原則”?!皩勺冃苑庋b原則”意味著兩點(diǎn):1 .一種可變性不應(yīng)當(dāng)散落在代碼的很多角落里,而應(yīng)當(dāng)被封裝到一個對象里面。同一種可變性的不同表象意味著同一個繼承等級結(jié)構(gòu)中的具體子類。2.一種可變性不應(yīng)當(dāng)與另一種可變性混合在一起。即類圖的繼承結(jié)構(gòu)一般不應(yīng)超過兩層。做到“開閉”原則不是一件容易的事,但是也有很多規(guī)律可循,這些規(guī)律同樣也是設(shè)計原則,它們是實(shí)現(xiàn)開閉原則的工具。里氏代換原則里氏代換原則:如果對每一個類型為T1的對象o1,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有對象o1都換成o2時,程序P的行為沒有變化,那么類型T2是T1的子類型。即如果一個軟

9、件實(shí)體使用的是基類的話那么也一定適用于子類。但反過來的代換不成立。如果有兩個具體類A和B之間的關(guān)系違反了里氏代換原則,可以在以下兩種重構(gòu)方案中選擇一種:1 .創(chuàng)建一個新的抽象類C,作為兩個具體類的超類,將A和B共同的行為移動到C中,從而解決A和B行為不完全一致的問題。2 .從B到A的繼承關(guān)系改寫為委派關(guān)系。依賴倒轉(zhuǎn)原則依賴倒轉(zhuǎn)原則講的是:要依賴于抽象,不要依賴于具體。即針對接口編程,不要針對實(shí)現(xiàn)編程。針對接口編程的意思是,應(yīng)當(dāng)使用接口和抽象類進(jìn)行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數(shù)據(jù)類型的轉(zhuǎn)換等。不要針對實(shí)現(xiàn)編程的意思就是說,不應(yīng)當(dāng)使用具體類進(jìn)行變量的類型聲明、參量的類型

10、聲明,方法的返還類型聲明,以及數(shù)據(jù)類型的轉(zhuǎn)換等。依賴倒轉(zhuǎn)原則雖然強(qiáng)大,但卻不易實(shí)現(xiàn),因?yàn)橐蕾嚨罐D(zhuǎn)的緣故,對象的創(chuàng)建很可能要使Page 4用對象工廠,以避免對具體類的直接引用,此原則的使用還會導(dǎo)致大量的類。維護(hù)這樣的系統(tǒng)需要較好的面向?qū)ο蟮脑O(shè)計知識。此外,依賴倒轉(zhuǎn)原則假定所有的具體類都是變化的,這也不總是正確的。有一些具體類可能是相當(dāng)穩(wěn)定、不會發(fā)生變化的,消費(fèi)這個具體類實(shí)例的客戶端完全可以依賴于這個具體類。接口隔離原則接口隔離原則講的是:使用多個專門的接口比使用單一的接口要好。從客戶的角度來說:一個類對另外一個類的依賴性應(yīng)當(dāng)是建立在最小的接口上的。如果客戶端只需要某一些方法的話,那么就應(yīng)當(dāng)向客戶

11、端提供這些需要的方法,而不要提供不需要的方法。提供接口意味著向客戶端作出承諾,過多的承諾會給系統(tǒng)的維護(hù)造成不必要的負(fù)擔(dān)。合成、聚合復(fù)用原則合成、聚合復(fù)用原則就是在一個新的對象里面使用一些已有的對象,使之成為新對象的一部份,新的對象通過向這些對象的委派達(dá)到復(fù)用已有功能的目的。這個原則有一個簡短的描述:要盡量使用合成、聚合,盡量不要使用繼承。合成、聚合有如下好處:新對象存取成分對象的唯一方法是通過成分對象的接口。這種復(fù)用是黑箱復(fù)用,因?yàn)槌煞謱ο蟮膬?nèi)部細(xì)節(jié)是新對象所看不到的。這種復(fù)用可以在運(yùn)行時間內(nèi)動態(tài)進(jìn)行,新對象可以動態(tài)的引用與成分對象類型相同的對象。 合成、聚合可以應(yīng)用到任何環(huán)境中去,而繼承只能

12、應(yīng)用到一些有限環(huán)境中去。導(dǎo)致錯誤的使用合成、聚合與繼承的一個常見原因是錯誤的把“Has-a”關(guān)系當(dāng)作“Is-a”關(guān)系。如果兩個類是“Has-a”關(guān)系那么應(yīng)使用合成、聚合,如果是“Is-a”關(guān)系那么可使用繼承。迪米特法則迪米特法則說的是一個對象應(yīng)該對其它對象有盡可能少的了解。即只與你直接的朋友通信,不要跟陌生人說話。如果需要和陌生人通話,而你的朋友與陌生人是朋友,那么可以將你對陌生人的調(diào)用由你的朋友轉(zhuǎn)發(fā),使得某人只知道朋友,不知道陌生人。換言之,某人會認(rèn)為他所調(diào)用的是朋友的方法。以下條件稱為朋友的條件:當(dāng)前對象本身。以參量的形式傳入到當(dāng)前對象方法中的對象。當(dāng)前對象的實(shí)例變量直接引用的對象。當(dāng)前對

13、象的實(shí)例變量如果是一個聚集,那么聚集中的元素也都是朋友。當(dāng)前對象所創(chuàng)建的對象。任何一個對象,如果滿足上面的條件之一,就是當(dāng)前對象的朋友,否則就是陌生人。迪米特法則的主要用意是控制信息的過載,在將其運(yùn)用到系統(tǒng)設(shè)計中應(yīng)注意以下幾點(diǎn): 在類的劃分上,應(yīng)當(dāng)創(chuàng)建有弱耦合的類。類之間的耦合越弱,就越有利于復(fù)用。在類的結(jié)構(gòu)設(shè)計上,每一個類都應(yīng)當(dāng)盡量降低成員的訪問權(quán)限。一個類不應(yīng)當(dāng)public自己的屬性,而應(yīng)當(dāng)提供取值和賦值的方法讓外界間接訪問自己的屬性。Page 5在類的設(shè)計上,只要有可能,一個類應(yīng)當(dāng)設(shè)計成不變類。在對其它對象的引用上,一個類對其它對象的引用應(yīng)該降到最低。一個良好的面向?qū)ο笤O(shè)計需要遵循一些基

14、本原則,如單一職責(zé)原則(SRP)、開放-封閉原則(OCP)、Liskov替換原則(LSP)、依賴倒置原則(DIP)、接口分離原則(ISP)等。1、 單一職責(zé)原則(SRP)描述:就一個類而言,應(yīng)該僅有一個引起它變化的原因。應(yīng)用:在構(gòu)造對象時,將對象的不同職責(zé)分離至兩個或多個類中,確保引起該類變化的原因只有一個。帶來的好處:提高內(nèi)聚、降低耦合。個人觀點(diǎn):該原則可以有效降低耦合,減少對不必要資源的引用。但后果是造成源文件增多,給管理帶來不便,所以在實(shí)際應(yīng)用中,可以對經(jīng)常使用或經(jīng)常需要改動的模塊應(yīng)用該原則。2、 開放-封閉原則(OCP)描述:"對于擴(kuò)展是開放的"(Open for

15、extension)。這意味著模塊的行為是可以擴(kuò)展的。當(dāng)應(yīng)用的需求改變時,可以對模塊進(jìn)行擴(kuò)展,使其具有滿足改變的新行為。也就是說,我們可以改變模塊的功能。"對于更改是封閉的"(Close for modification)。對模塊行為進(jìn)行擴(kuò)展時,不必改動模塊的源代碼或者二進(jìn)制代碼。應(yīng)用:高級語言中的接口與虛擬類。帶來的好處:提高靈活性、可重用性、可維護(hù)性。個人觀點(diǎn):OCP的關(guān)鍵是抽象,抽象的目的是創(chuàng)建一個固定卻能夠描述一組任意個可能行為的基類。而這一組可能的行為則表現(xiàn)為派生類。對于基類的更改是封閉的,所以它里邊的方法一旦確定就不能更改(對接口里的方法進(jìn)行更改將帶來災(zāi)難性的后

16、果)。模塊通過抽象基類進(jìn)行引用,對派生類的擴(kuò)展并不影響整個模塊,所以它是開放的。遵循OCP的代價也是昂貴的,創(chuàng)建正確的抽象是要花費(fèi)開發(fā)時間和精力的,同時抽象也增加了軟件設(shè)計的復(fù)雜性。因此有效的預(yù)知變化是OCP設(shè)計的要點(diǎn),這需要我們進(jìn)行適當(dāng)?shù)恼{(diào)查,提出正確的問題,并利用我們的經(jīng)驗(yàn)和一般常識來做出判斷。正確的做法是,只對程序中頻繁變化的部分做出抽象,拒絕不成熟的抽象和抽象本身一樣重要。3、 Liskov替換原則(LSP)描述:若對每個類型S的對象O1,都存在一個類型T的對象O2,使得在所有針對T編寫的程序P中,用O1替換O2后,程序P行為功能不變,則S是T的子類型。應(yīng)用:在實(shí)現(xiàn)繼承時,子類型(su

17、btype)必須能替換掉它們的基類型(base type)。如果一個軟件實(shí)體使用的是基類的話那么也一定適用于子類。但反過來的代換不成立。個人觀點(diǎn): LSP是使OCP成為可能的主要原則之一,對LSP的違反將導(dǎo)致對OCP的違反,同時二者是OOD中抽象和多態(tài)的理論基礎(chǔ),在OOPL中表現(xiàn)為繼承。在高級語言(JAVA、C#)中,只要我們嚴(yán)格按照接口和虛擬類的語法規(guī)范來做就能很好遵循此原則,另外我們還應(yīng)該避免一些更微妙的違規(guī)情況。舉個例子,正方形和矩形,矩形可以做為正方形的基類,因?yàn)檎叫我彩且环N矩形,但對于正方形來說,setWidth()和setHeight()是冗余的,且容易引起錯誤,這樣的設(shè)計就違反

18、了LSP原則。如果有兩個具體類A和B之間的關(guān)系違反了LSP,Page 6可以在以下兩種重構(gòu)方案中選擇一種:1 .創(chuàng)建一個新的抽象類C,作為兩個具體類的超類,將A和B共同的行為移動到C中,從而解決A和B行為不完全一致的問題。 2 .從B到A的繼承關(guān)系改寫為委派關(guān)系。4、 依賴倒置原則(DIP)描述:A .高層模塊不應(yīng)該依賴于低層模塊。二者都應(yīng)該依賴于抽象。B .抽象不應(yīng)該依賴于細(xì)節(jié)。細(xì)節(jié)應(yīng)該依賴于抽象。應(yīng)用:要依賴抽象,不要依賴于具體。即針對接口編程,不要針對實(shí)現(xiàn)編程。針對接口編程的意思是,應(yīng)當(dāng)使用接口和抽象類進(jìn)行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數(shù)據(jù)類型的轉(zhuǎn)換等。不要針對

19、實(shí)現(xiàn)編程的意思就是說,不應(yīng)當(dāng)使用具體類進(jìn)行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數(shù)據(jù)類型的轉(zhuǎn)換等。結(jié)論:DIP雖然強(qiáng)大,但卻不易實(shí)現(xiàn),因?yàn)橐蕾嚨罐D(zhuǎn)的緣故,對象的創(chuàng)建很可能要使用對象工廠,以避免對具體類的直接引用,此原則的使用將導(dǎo)致大量的類文件。給維護(hù)帶來不必要的麻煩。所以,正確的做法是只對程序中頻繁變化的部分進(jìn)行依賴倒置。5、 接口隔離原則(ISP)描述:不要強(qiáng)迫客戶依賴于它們不用的方法。應(yīng)用:一個類對另外一個類的依賴性應(yīng)當(dāng)是建立在最小的接口上的。如果客戶端只需要某一些方法的話,那么就應(yīng)當(dāng)向客戶端提供這些需要的方法,而不要提供不需要的方法。提供接口意味著向客戶端作出承諾,過多

20、的承諾會給系統(tǒng)的維護(hù)造成不必要的負(fù)擔(dān)。結(jié)論:使用多個專門的接口比使用單一的接口要好。遵循以上原則,可以使我們的軟件更具靈活性,強(qiáng)壯性。但靈活是需要付出代價的,由多態(tài)帶來的性能損失就是最明顯的一個問題。所以我們需要權(quán)衡,需要做出選擇,在靈活與性能之間做出選擇。追本溯源,促使我們使用這些原則的原因是為了滿足需求的變更,于是需求分析就顯得格外重要。然而不管怎么充分的需求分析都可能遭遇需求變更,于是預(yù)測變化就成了一個讓人頭痛的事。還是讓我們來看看敏捷設(shè)計(XP)是怎么解決這些問題的:"敏捷開發(fā)人員不會對一個龐大的預(yù)先設(shè)計應(yīng)用那些原則和模式,相反,這些原則和模式被應(yīng)用在一次次的迭代中,力圖使代

21、碼以及代碼所表達(dá)的設(shè)計保持干凈。"也就是說敏捷設(shè)計通過快速的迭代來刺激變化,讓這些變化及早暴露,再根據(jù)變化進(jìn)行相應(yīng)改動。很明顯這要比一次性完整設(shè)計輕松容易的多。最后引用透明在書評中的一句話來結(jié)束這篇blog。"軟件開發(fā)的全部藝術(shù)就是權(quán)衡:在簡單與復(fù)雜之間權(quán)衡,在一種方案與另一種方案之間權(quán)衡。如果把每個問題、每個權(quán)衡的利弊都考慮得清清楚楚,恐怕開發(fā)一個應(yīng)用程序的成本會高得驚人。所以,很多時候我們更依賴自己的審美眼光,用平靜的心去設(shè)計一個賞心悅目的系統(tǒng)。"Page 761條Java面向?qū)ο笤O(shè)計的經(jīng)驗(yàn)原則(1)所有數(shù)據(jù)都應(yīng)該隱藏在所在的類的內(nèi)部。(2)類的使用者必須依賴

22、類的共有接口,但類不能依賴它的使用者。(3)盡量減少類的協(xié)議中的消息。(4)實(shí)現(xiàn)所有類都理解的最基本公有接口例如,拷貝操作(深拷貝和淺拷貝)、相等性判斷、正確輸出內(nèi)容、從ASCII描述解析等等.(5)不要把實(shí)現(xiàn)細(xì)節(jié)(例如放置共用代碼的私有函數(shù))放到類的公有接口中。如果類的兩個方法有一段公共代碼,那么就可以創(chuàng)建一個防止這些公共代碼的私有函數(shù)。(6)不要以用戶無法使用或不感興趣的東西擾亂類的公有接口。(7)類之間應(yīng)該零耦合,或者只有導(dǎo)出耦合關(guān)系。也即,一個類要么同另一個類毫無關(guān)系,要么只使用另一個類的公有接口中的操作。(8)類應(yīng)該只表示一個關(guān)鍵抽象。包中的所有類對于同一類性質(zhì)的變化應(yīng)該是共同封閉的

23、。一個變化若對一個包影響,則將對包中的所有類產(chǎn)生影響,而對其他的包不造成任何影響.(9)把相關(guān)的數(shù)據(jù)和行為集中放置。設(shè)計者應(yīng)當(dāng)留意那些通過get之類操作從別的對象中獲取數(shù)據(jù)的對象。這種類型的行為暗示著這條經(jīng)驗(yàn)原則被違反了。(10)把不相關(guān)的信息放在另一個類中(也即:互不溝通的行為)。朝著穩(wěn)定的方向進(jìn)行依賴。(11)確保你為之建模的抽象概念是類,而不只是對象扮演的角色。類應(yīng)當(dāng)統(tǒng)一地共享工作。(13)在你的系統(tǒng)中不要創(chuàng)建全能類/對象。對名字包含Driver、Manager、System、Susystem的類要特別多加小心。規(guī)劃一個接口而不是實(shí)現(xiàn)一個接口。(14)對公共接口中定義了大量訪問方法的類多

24、加小心。大量訪問方法意味著相關(guān)數(shù)據(jù)和行為沒有集中存放。(15)對包含太多互不溝通的行為的類多加小心。這個問題的另一表現(xiàn)是在你的應(yīng)用程序中的類的公有接口中創(chuàng)建了很多的get和set函數(shù)。Page 8(16)在由同用戶界面交互的Java面向?qū)ο竽P蜆?gòu)成的應(yīng)用程序中,模型不應(yīng)該依賴于界面,界面則應(yīng)當(dāng)依賴于模型。(17)盡可能地按照現(xiàn)實(shí)世界建模(我們常常為了遵守系統(tǒng)功能分布原則、避免全能類原則以及集中放置相關(guān)數(shù)據(jù)和行為的原則而違背這條原則).(18)從你的設(shè)計中去除不需要的類。一般來說,我們會把這個類降級成一個屬性。(19)去除系統(tǒng)外的類。系統(tǒng)外的類的特點(diǎn)是,抽象地看它們只往系統(tǒng)領(lǐng)域發(fā)送消息但并不接受

25、系統(tǒng)領(lǐng)域內(nèi)其他類發(fā)出的消息。(20)不要把操作變成類。質(zhì)疑任何名字是動詞或者派生自動詞的類,特別是只有一個有意義行為的類??紤]一下那個有意義的行為是否應(yīng)當(dāng)遷移到已經(jīng)存在或者尚未發(fā)現(xiàn)的某個類中。(21)我們在創(chuàng)建應(yīng)用程序的分析模型時常常引入代理類。在設(shè)計階段,我們常會發(fā)現(xiàn)很多代理沒有用的,應(yīng)當(dāng)去除。(22)盡量減少類的協(xié)作者的數(shù)量。一個類用到的其他類的數(shù)目應(yīng)當(dāng)盡量少。(23)盡量減少類和協(xié)作者之間傳遞的消息的數(shù)量。(24)盡量減少類和協(xié)作者之間的協(xié)作量,也即:減少類和協(xié)作者之間傳遞的不同消息的數(shù)量。(25)盡量減少類的扇出,也即:減少類定義的消息數(shù)和發(fā)送的消息數(shù)的乘積。(26)如果類包含另一個類

26、的對象,那么包含類應(yīng)當(dāng)給被包含的對象發(fā)送消息。也即:包含關(guān)系總是意味著使用關(guān)系。(27)類中定義的大多數(shù)方法都應(yīng)當(dāng)在大多數(shù)時間里使用大多數(shù)數(shù)據(jù)成員。(28)類包含的對象數(shù)目不應(yīng)當(dāng)超過開發(fā)者短期記憶的容量。這個數(shù)目常常是6.當(dāng)類包含多于6個數(shù)據(jù)成員時,可以把邏輯相關(guān)的數(shù)據(jù)成員劃分為一組,然后用一個新的包含類去包含這一組成員。(29)讓系統(tǒng)功能在窄而深的繼承體系中垂直分布。(30)在實(shí)現(xiàn)語義約束時,最好根據(jù)類定義來實(shí)現(xiàn)。這常常會導(dǎo)致類泛濫成災(zāi),在這種情況下,約束應(yīng)當(dāng)在類的行為中實(shí)現(xiàn),通常是在構(gòu)造函數(shù)中實(shí)現(xiàn),但不是必須如此。Page 9(31)在類的構(gòu)造函數(shù)中實(shí)現(xiàn)語義約束時,把約束測試放在構(gòu)造函數(shù)領(lǐng)

27、域所允許的盡量深的包含層次中。(32)Java面向?qū)ο笾?,約束所依賴的語義信息如果經(jīng)常改變,那么最好放在一個集中式的第3方對象中。(33)約束所依賴的語義信息如果很少改變,那么最好分布在約束所涉及的各個類中。(34)類必須知道它包含什么,但是不能知道誰包含它。(35)共享字面范圍(也就是被同一個類所包含)的對象相互之間不應(yīng)當(dāng)有使用關(guān)系。(36)繼承只應(yīng)被用來為特化層次結(jié)構(gòu)建模。(37)派生類必須知道基類,基類不應(yīng)該知道關(guān)于它們的派生類的任何信息。(38)基類中的所有數(shù)據(jù)都應(yīng)當(dāng)是私有的,不要使用保護(hù)數(shù)據(jù)。類的設(shè)計者永遠(yuǎn)都不應(yīng)該把類的使用者不需要的東西放在公有接口中。(39)在理論上,繼承層次體系

28、應(yīng)當(dāng)深一點(diǎn),越深越好。(40)在實(shí)踐中,繼承層次體系的深度不應(yīng)當(dāng)超出一個普通人的短期記憶能力。一個廣為接受的深度值是6.(41)所有的抽象類都應(yīng)當(dāng)是基類。(42)所有的基類都應(yīng)當(dāng)是抽象類。(43)把數(shù)據(jù)、行為和/或接口的共性盡可能地放到繼承層次體系的高端。(44)如果兩個或更多個類共享公共數(shù)據(jù)(但沒有公共行為),那么應(yīng)當(dāng)把公共數(shù)據(jù)放在一個類中,每個共享這個數(shù)據(jù)的類都包含這個類。(45)如果兩個或更多個類有共同的數(shù)據(jù)和行為(就是方法),那么這些類的每一個都應(yīng)當(dāng)從一個表示了這些數(shù)據(jù)和方法的公共基類繼承。(46)如果兩個或更多個類共享公共接口(指的是消息,而不是方法),那么只有他們需要被多態(tài)地使用時

29、,他們才應(yīng)當(dāng)從一個公共基類繼承。(47)對對象類型的顯示的分情況分析一般是錯誤的。在大多數(shù)這樣的情況下,設(shè)計者應(yīng)當(dāng)使用多態(tài)。(48)對屬性值的顯示的分情況分析常常是錯誤的。類應(yīng)當(dāng)解耦合成一個繼承層次結(jié)構(gòu),每個屬性值都被變換成一個派生類。Page 10(49)不要通過繼承關(guān)系來為類的動態(tài)語義建模。試圖用靜態(tài)語義關(guān)系來為動態(tài)語義建模會導(dǎo)致在運(yùn)行時切換類型。(50)不要把類的對象變成派生類。對任何只有一個實(shí)例的派生類都要多加小心。(51)如果你覺得需要在運(yùn)行時刻創(chuàng)建新的類,那么退后一步以認(rèn)清你要創(chuàng)建的是對象?,F(xiàn)在,把這些對象概括成一個類。(52)在派生類中用空方法(也就是什么也不做的方法)來覆寫基類

30、中的方法應(yīng)當(dāng)是非法的。(53)不要把可選包含同對繼承的需要相混淆。把可選包含建模成繼承會帶來泛濫成災(zāi)的類。(54)在創(chuàng)建繼承層次時,試著創(chuàng)建可復(fù)用的框架,而不是可復(fù)用的組件。(55)如果你在設(shè)計中使用了多重繼承,先假設(shè)你犯了錯誤。如果沒犯錯誤,你需要設(shè)法證明。(56)只要在Java面向?qū)ο笤O(shè)計中用到了繼承,問自己兩個問題:(1)派生類是否是它繼承的那個東西的一個特殊類型?(2)基類是不是派生類的一部分?(57)如果你在一個面向?qū)ο笤O(shè)計中發(fā)現(xiàn)了多重繼承關(guān)系,確保沒有哪個基類實(shí)際上是另一個基類的派生類。(58)在面向?qū)ο笤O(shè)計中如果你需要在包含關(guān)系和關(guān)聯(lián)關(guān)系間作出選擇,請選擇包含關(guān)系。(59)不要把

31、全局?jǐn)?shù)據(jù)或全局函數(shù)用于類的對象的薄記工作。應(yīng)當(dāng)使用類變量或類方法。(60)Java面向?qū)ο笤O(shè)計者不應(yīng)當(dāng)讓物理設(shè)計準(zhǔn)則來破壞他們的邏輯設(shè)計。但是,在對邏輯設(shè)計作出決策的過程中我們經(jīng)常用到物理設(shè)計準(zhǔn)則。(61)不要繞開公共接口去修改對象的狀態(tài)。面向?qū)ο蠓治?面向?qū)ο蠓治觯∣bject-Oriented Analysis,OOA,面向?qū)ο蠓治龇椒ǎ?,是在一個系統(tǒng)的開發(fā)過程中進(jìn)行了系統(tǒng)業(yè)務(wù)調(diào)查以后,按照面向?qū)ο蟮乃枷雭矸治鰡栴}。OOA與結(jié)構(gòu)化分析有較大的區(qū)別。OOA所強(qiáng)調(diào)的是在系統(tǒng)調(diào)查資料的基礎(chǔ)上,針對OO方法所需要的素材進(jìn)行的歸類分析和整理,而不是對管理業(yè)務(wù)現(xiàn)狀和方法的分析。OOA(面向?qū)ο蟮姆治觯?/p>

32、模型由5個層次(主題層、對象類層、結(jié)構(gòu)層、屬性層和服務(wù)層)和5個活動(標(biāo)識對象類、標(biāo)識結(jié)構(gòu)、定義主題、定義屬性和定義服務(wù))組成。在這種方法中定義了兩種對象類之間的結(jié)構(gòu),一種稱為分類結(jié)構(gòu),一種稱為組裝結(jié)構(gòu)。分類結(jié)構(gòu)就是所謂的一般與特殊的關(guān)系。組裝結(jié)構(gòu)則反映了對象之間的整體與部分的關(guān)系。Page 11OOA在定義屬性的同時,要識別實(shí)例連接。實(shí)例連接是一個實(shí)例與另一個實(shí)例的映射關(guān)系。OOA在定義服務(wù)的同時要識別連接。當(dāng)一個對象需要向另一對象發(fā)送消息時,它們之間就存在消息連接。OOA 中的5個層次和5個活動繼續(xù)貫穿在(畫向?qū)ο蟮脑O(shè)計)過程中。OOD模型由4個部分組成。它們分別是設(shè)計問題域部分、設(shè)計人機(jī)

33、交互部分、設(shè)計任務(wù)管理部分設(shè)計數(shù)據(jù)管理部分。一、OOA的主要原則。(1)抽象:從許多事物中舍棄個別的、非本質(zhì)的特征,抽取共同的、本質(zhì)性的特征,就叫作抽象。抽象是形成概念的必須手段。抽象原則有兩方面的意義:第一,盡管問題域中的事物是很復(fù)雜的,但是分析員并不需要了解和描述它們的一切,只需要分析研究其中與系統(tǒng)目標(biāo)有關(guān)的事物及其本質(zhì)性特征。第二,通過舍棄個體事物在細(xì)節(jié)上的差異,抽取其共同特征而得到一批事物的抽象概念。抽象是中使用最為廣泛的原則。抽象原則包括過程抽象和數(shù)據(jù)抽象兩個方面。過程抽象是指,任何一個完成確定功能的操作序列,其使用者都可以把它看作一個單一的實(shí)體,盡管實(shí)際上它可能是由一系列更低級的操

34、作完成的。 數(shù)據(jù)抽象是根據(jù)施加于數(shù)據(jù)之上的操作來定義數(shù)據(jù),并限定數(shù)據(jù)的值只能由這些操作來修改和觀察。數(shù)據(jù)抽象是OOA的核心原則。它強(qiáng)調(diào)把數(shù)據(jù)(屬性)和操作(服務(wù))結(jié)合為一個不可分的系統(tǒng)單位(即對象),對象的外部只需要知道它做什么,而不必知道它如何做。(2)封裝就是把對象的屬性和服務(wù)結(jié)合為一個不可分的系統(tǒng)單位,并盡可能隱蔽對象的內(nèi)部細(xì)節(jié)。(3)繼承:特殊類的對象擁有的其一般類的全部屬性與服務(wù),稱作特殊類對一般類的繼承。在OOA中運(yùn)用繼承原則,就是在每個由一般類和特殊類形成的一般特殊結(jié)構(gòu)中,把一般類的對象實(shí)例和所有特殊類的對象實(shí)例都共同具有的屬性和服Page 12務(wù),一次性地在一般類中進(jìn)行顯式的定義。在特殊類中不再重復(fù)地定義一般類中已定義的東西,但是在語義上,特殊類卻自動地、隱含地?fù)碛兴囊话泐悾ㄒ约八懈蠈拥囊话泐悾┲卸x的全部屬性和服務(wù)。繼承原則的好處是:使系統(tǒng)模型比較簡練也比較清晰。(4)分類:就是把具有相同屬性和服務(wù)的對象劃分為一類,用類作為這些對象的抽象描述。分類原則實(shí)際上是抽象原則

溫馨提示

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

評論

0/150

提交評論