dw做網(wǎng)站怎么用到j(luò)ava免費發(fā)帖推廣網(wǎng)站
面向?qū)ο笤O(shè)計原則
- 面向?qū)ο笤O(shè)計原則簡介
- 單一職責(zé)原則
- 單一職責(zé)原則定義
- 單一職責(zé)原則分析
- 單一職責(zé)原則實例
- 開閉原則
- 開閉原則定義
- 開閉原則分析
- 開閉原則實例
- 里氏代換原則
- 里氏代換原則定義
- 里氏代換原則分析
- 依賴倒轉(zhuǎn)原則
- 依賴倒轉(zhuǎn)原則定義
- 依賴倒轉(zhuǎn)原則分析
- 依賴倒轉(zhuǎn)原則實例
- 接口隔離原則
- 接口隔離原則定義
- 接口隔離原則分析
- 接口隔離原則實例
- 合成復(fù)用原則
- 合成復(fù)用原則定義
- 合成復(fù)用原則分析
- 合成復(fù)用原則實例
- 迪米特法則
- 迪米特法則定義
- 迪米特法則分析
- 狹義的迪米特法則:
- 廣義的迪米特法則:
- 迪米特法則實例
- 小結(jié)
面向?qū)ο笤O(shè)計原則簡介
常用的面向?qū)ο笤O(shè)計原則包括7個,這些原則并不是孤立存在的,它們相互依賴,相互補充。
單一職責(zé)原則
單一職責(zé)原則定義
單一職責(zé)原則(Single Responsibility Principle, SRP)定義如下:
一個對象應(yīng)該只包含單一的職責(zé),并且該職責(zé)被完整地封裝在一個類中。 其英文定義為: Every object should have a
single responsibility, and that responsibility should be entirely
encapsulated by the class. 另一種定義方式如下: 就一個類而言,應(yīng)該僅有一個引起它變化的原因。 其英文定義為:
There should never be more than one reason for a class to change.
單一職責(zé)原則分析
一個類(或者大到模塊,小到方法)承擔的職責(zé)越多,它被復(fù)用的可能性越小,而且如果一個類承擔的職責(zé)過多,就相當于將這些職責(zé)耦合在一起,當其中一個職責(zé)變化時,可能會影響其他職責(zé)的運作。
類的職責(zé)主要包括兩個方面:數(shù)據(jù)職責(zé)和行為職責(zé),數(shù)據(jù)職責(zé)通過其屬性來體現(xiàn),而行為職責(zé)通過其方法來體現(xiàn)。
單一職責(zé)原則是實現(xiàn)高內(nèi)聚、低耦合的指導(dǎo)方針,在很多代碼重構(gòu)手法中都能找到它的存在,它是最簡單但又最難運用的原則,需要設(shè)計人員發(fā)現(xiàn)類的不同職責(zé)并將其分離,而發(fā)現(xiàn)類的多重職責(zé)需要設(shè)計人員具有較強的分析設(shè)計能力和相關(guān)重構(gòu)經(jīng)驗。
單一職責(zé)原則實例
實例說明
某基于Java的C/S系統(tǒng)的“登錄功能”通過如下登錄類(Login)實現(xiàn):
現(xiàn)使用單一職責(zé)原則對其進行重構(gòu)。
開閉原則
開閉原則定義
開閉原則(Open-Closed Principle, OCP)定義如下:
一個軟件實體應(yīng)當對擴展開放,對修改關(guān)閉。也就是說在設(shè)計一個模塊的時候,應(yīng)當使這個模塊可以在不被修改的前提下被擴展,即實現(xiàn)在不修改源代碼的情況下改變這個模塊的行為。
其英文定義為: Software entities should be open for extension, but closed for
modification.
開閉原則分析
抽象化是開閉原則的關(guān)鍵。
開閉原則還可以通過一個更加具體的“對可變性封裝原則”來描述,對可變性封裝原則(Principle of Encapsulation of Variation, EVP)要求找到系統(tǒng)的可變因素并將其封裝起來。
開閉原則實例
實例說明
某圖形界面系統(tǒng)提供了各種不同形狀的按鈕,客戶端代碼可針對這些按鈕進行編程,用戶可能會改變需求要求使用不同的按鈕,原始設(shè)計方案如圖所示:
現(xiàn)對該系統(tǒng)進行重構(gòu),使之滿足開閉原則的要求。
里氏代換原則
里氏代換原則定義
里氏代換原則(Liskov Substitution Principle, LSP)有兩種定義方式,第一種定義方式相對嚴格,其定義如下:
如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程序P在所有的對象o1都代換成o2時,程序P的行為沒有變化,那么類型S是類型T的子類型。
其英文定義為:
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
第二種更容易理解的定義方式如下:
所有引用基類(父類)的地方必須能透明地使用其子類的對象。
其英文定義為:
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
里氏代換原則分析
里氏代換原則可以通俗表述為:在軟件中如果能夠使用基類對象,那么一定能夠使用其子類對象。把基類都替換成它的子類,程序?qū)⒉粫a(chǎn)生任何錯誤和異常,反過來則不成立,如果一個軟件實體使用的是一個子類的話,那么它不一定能夠使用基類。
里氏代換原則是實現(xiàn)開閉原則的重要方式之一,由于使用基類對象的地方都可以使用子類對象,因此在程序中盡量使用基類類型來對對象進行定義,而在運行時再確定其子類類型,用子類對象來替換父類對象。
依賴倒轉(zhuǎn)原則
依賴倒轉(zhuǎn)原則定義
依賴倒轉(zhuǎn)原則(Dependence Inversion Principle, DIP)的定義如下:
高層模塊不應(yīng)該依賴低層模塊,它們都應(yīng)該依賴抽象。抽象不應(yīng)該依賴于細節(jié),細節(jié)應(yīng)該依賴于抽象。
其英文定義為:
High level modules should not depend upon low level modules, both should depend upon abstractions. Abstractions should not depend upon details, details should depend upon abstractions.
另一種表述為:
要針對接口編程,不要針對實現(xiàn)編程。
其英文定義為:
Program to an interface, not an implementation.
依賴倒轉(zhuǎn)原則分析
類之間的耦合
零耦合關(guān)系
具體耦合關(guān)系
抽象耦合關(guān)系
依賴倒轉(zhuǎn)原則要求客戶端依賴于抽象耦合,以抽象方式耦合是依賴倒轉(zhuǎn)原則的關(guān)鍵。
依賴倒轉(zhuǎn)原則實例
實例說明
某系統(tǒng)提供一個數(shù)據(jù)轉(zhuǎn)換模塊,可以將來自不同數(shù)據(jù)源的數(shù)據(jù)轉(zhuǎn)換成多種格式,如可以轉(zhuǎn)換來自數(shù)據(jù)庫的數(shù)據(jù)(DatabaseSource)、也可以轉(zhuǎn)換來自文本文件的數(shù)據(jù)(TextSource),轉(zhuǎn)換后的格式可以是XML文件(XMLTransformer)、也可以是XLS文件(XLSTransformer)等。
實例說明
由于需求的變化,該系統(tǒng)可能需要增加新的數(shù)據(jù)源或者新的文件格式,每增加一個新的類型的數(shù)據(jù)源或者新的類型的文件格式,客戶類MainClass都需要修改源代碼,以便使用新的類,但違背了開閉原則?,F(xiàn)使用依賴倒轉(zhuǎn)原則對其進行重構(gòu)。
接口隔離原則
接口隔離原則定義
接口隔離原則(Interface Segregation Principle, ISP)的定義如下:
客戶端不應(yīng)該依賴那些它不需要的接口。
其英文定義為:
Clients should not be forced to depend upon interfaces that they do not use.
注意,在該定義中的接口指的是所定義的方法。
另一種定義方法如下:
一旦一個接口太大,則需要將它分割成一些更細小的接口,使用該接口的客戶端僅需知道與之相關(guān)的方法即可。
其英文定義為:
Once an interface has gotten too ‘fat’ it needs to be split into smaller and more specific interfaces so that any clients of the interface will only know about the methods that pertain to them.
接口隔離原則分析
接口隔離原則是指使用多個專門的接口,而不使用單一的總接口。每一個接口應(yīng)該承擔一種相對獨立的角色,不多不少,不干不該干的事,該干的事都要干。
(1) 一個接口就只代表一個角色,每個角色都有它特定的一個接口,此時這個原則可以叫做“角色隔離原則”。
(2) 接口僅僅提供客戶端需要的行為,即所需的方法,客戶端不需要的行為則隱藏起來,應(yīng)當為客戶端提供盡可能小的單獨的接口,而不要提供大的總接口。
使用接口隔離原則拆分接口時,首先必須滿足單一職責(zé)原則,將一組相關(guān)的操作定義在一個接口中,且在滿足高內(nèi)聚的前提下,接口中的方法越少越好。
可以在進行系統(tǒng)設(shè)計時采用定制服務(wù)的方式,即為不同的客戶端提供寬窄不同的接口,只提供用戶需要的行為,而隱藏用戶不需要的行為。
接口隔離原則實例
實例說明
下圖展示了一個擁有多個客戶類的系統(tǒng),在系統(tǒng)中定義了一個巨大的接口(胖接口)AbstractService來服務(wù)所有的客戶類。可以使用接口隔離原則對其進行重構(gòu)。
重構(gòu)后
合成復(fù)用原則
合成復(fù)用原則定義
合成復(fù)用原則(Composite Reuse Principle, CRP)又稱為組合/聚合復(fù)用原則(Composition/ Aggregate Reuse Principle, CARP),其定義如下:
盡量使用對象組合,而不是繼承來達到復(fù)用的目的。
其英文定義為:
Favor composition of objects over inheritance as a reuse mechanism.
合成復(fù)用原則分析
合成復(fù)用原則就是指在一個新的對象里通過關(guān)聯(lián)關(guān)系(包括組合關(guān)系和聚合關(guān)系)來使用一些已有的對象,使之成為新對象的一部分;新對象通過委派調(diào)用已有對象的方法達到復(fù)用其已有功能的目的。簡言之:要盡量使用組合/聚合關(guān)系,少用繼承。
組合/聚合可以使系統(tǒng)更加靈活,類與類之間的耦合度降低,一個類的變化對其他類造成的影響相對較少,因此一般首選使用組合/聚合來實現(xiàn)復(fù)用;其次才考慮繼承,在使用繼承時,需要嚴格遵循里氏代換原則,有效使用繼承會有助于對問題的理解,降低復(fù)雜度,而濫用繼承反而會增加系統(tǒng)構(gòu)建和維護的難度以及系統(tǒng)的復(fù)雜度,因此需要慎重使用繼承復(fù)用。
合成復(fù)用原則實例
實例說明
某教學(xué)管理系統(tǒng)部分數(shù)據(jù)庫訪問類設(shè)計如圖所示:
實例說明
如果需要更換數(shù)據(jù)庫連接方式,如原來采用JDBC連接數(shù)據(jù)庫,現(xiàn)在采用數(shù)據(jù)庫連接池連接,則需要修改DBUtil類源代碼。如果StudentDAO采用JDBC連接,但是TeacherDAO采用連接池連接,則需要增加一個新的DBUtil類,并修改StudentDAO或TeacherDAO的源代碼,使之繼承新的數(shù)據(jù)庫連接類,這將違背開閉原則,系統(tǒng)擴展性較差。
現(xiàn)使用合成復(fù)用原則對其進行重構(gòu)。
迪米特法則
迪米特法則定義
迪米特法則(Law of Demeter, LoD)又稱為最少知識原則(Least Knowledge Principle, LKP),它有多種定義方法,其中幾種典型定義如下:
(1) 不要和“陌生人”說話。英文定義為:Don’t talk to strangers.
(2) 只與你的直接朋友通信。英文定義為:Talk only to your immediate friends.
(3) 每一個軟件單位對其他的單位都只有最少的知識,而且局限于那些與本單位密切相關(guān)的軟件單位。英文定義為:Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
迪米特法則分析
迪米特法則來自于1987年秋美國東北大學(xué)(Northeastern University)一個名為“Demeter”的研究項目。
簡單地說,迪米特法則就是指一個軟件實體應(yīng)當盡可能少的與其他實體發(fā)生相互作用。這樣,當一個模塊修改時,就會盡量少的影響其他的模塊,擴展會相對容易,這是對軟件實體之間通信的限制,它要求限制軟件實體之間通信的寬度和深度。
在迪米特法則中,對于一個對象,其朋友包括以下幾類:
(1) 當前對象本身(this);
(2) 以參數(shù)形式傳入到當前對象方法中的對象;
(3) 當前對象的成員對象;
(4) 如果當前對象的成員對象是一個集合,那么集合中的元素也都是朋友;
(5) 當前對象所創(chuàng)建的對象。
任何一個對象,如果滿足上面的條件之一,就是當前對象的“朋友”,否則就是“陌生人”。
迪米特法則可分為狹義法則和廣義法則。在狹義的迪米特法則中,如果兩個類之間不必彼此直接通信,那么這兩個類就不應(yīng)當發(fā)生直接的相互作用,如果其中的一個類需要調(diào)用另一個類的某一個方法的話,可以通過第三者轉(zhuǎn)發(fā)這個調(diào)用。
狹義的迪米特法則:
可以降低類之間的耦合,但是會在系統(tǒng)中增加大量的小方法并散落在系統(tǒng)的各個角落,它可以使一個系統(tǒng)的局部設(shè)計簡化,因為每一個局部都不會和遠距離的對象有直接的關(guān)聯(lián),但是也會造成系統(tǒng)的不同模塊之間的通信效率降低,使得系統(tǒng)的不同模塊之間不容易協(xié)調(diào)。
廣義的迪米特法則:
指對對象之間的信息流量、流向以及信息的影響的控制,主要是對信息隱藏的控制。信息的隱藏可以使各個子系統(tǒng)之間脫耦,從而允許它們獨立地被開發(fā)、優(yōu)化、使用和修改,同時可以促進軟件的復(fù)用,由于每一個模塊都不依賴于其他模塊而存在,因此每一個模塊都可以獨立地在其他的地方使用。一個系統(tǒng)的規(guī)模越大,信息的隱藏就越重要,而信息隱藏的重要性也就越明顯。
迪米特法則的主要用途在于控制信息的過載:
在類的劃分上,應(yīng)當盡量創(chuàng)建松耦合的類,類之間的耦合度越低,就越有利于復(fù)用,一個處在松耦合中的類一旦被修改,不會對關(guān)聯(lián)的類造成太大波及;
在類的結(jié)構(gòu)設(shè)計上,每一個類都應(yīng)當盡量降低其成員變量和成員函數(shù)的訪問權(quán)限;
在類的設(shè)計上,只要有可能,一個類型應(yīng)當設(shè)計成不變類;
在對其他類的引用上,一個對象對其他對象的引用應(yīng)當降到最低。
迪米特法則實例
實例說明
某系統(tǒng)界面類(如Form1、Form2等類)與數(shù)據(jù)訪問類(如DAO1、DAO2等類)之間的調(diào)用關(guān)系較為復(fù)雜,如圖所示:
重構(gòu)后
小結(jié)
對于面向?qū)ο蟮能浖到y(tǒng)設(shè)計來說,在支持可維護性的同時,需要提高系統(tǒng)的可復(fù)用性。
軟件的復(fù)用可以提高軟件的開發(fā)效率,提高軟件質(zhì)量,節(jié)約開發(fā)成本,恰當?shù)膹?fù)用還可以改善系統(tǒng)的可維護性。
單一職責(zé)原則要求在軟件系統(tǒng)中,一個類只負責(zé)一個功能領(lǐng)域中的相應(yīng)職責(zé)。
開閉原則要求一個軟件實體應(yīng)當對擴展開放,對修改關(guān)閉,即在不修改源代碼的基礎(chǔ)上擴展一個系統(tǒng)的行為。
里氏代換原則可以通俗表述為在軟件中如果能夠使用基類對象,那么一定能夠使用其子類對象。
依賴倒轉(zhuǎn)原則要求抽象不應(yīng)該依賴于細節(jié),細節(jié)應(yīng)該依賴于抽象;要針對接口編程,不要針對實現(xiàn)編程。
接口隔離原則要求客戶端不應(yīng)該依賴那些它不需要的接口,即將一些大的接口細化成一些小的接口供客戶端使用。
合成復(fù)用原則要求復(fù)用時盡量使用對象組合,而不使用繼承。
迪米特法則要求一個軟件實體應(yīng)當盡可能少的與其他實體發(fā)生相互作用。