在面向對象的軟件系統(tǒng)設計中秕豫,可維護性硕并,可復用性是衡量一個軟件系統(tǒng)是否健壯的重要指標膊升。而可維護性和可復用性是可以遵從基本的準則來得以實現(xiàn)怎炊。而這些準則就是面向對象設計的基本原則。面向對象的設計原則一共有7種廓译,這些原則都是以前的軟件工程師在實踐中總結的基本原則评肆,經得起項目的考驗,時間的檢驗非区,這些原則也是設計模式的基礎瓜挽。每種原則都蘊含面向對象的思想,從而從不同的緯度去提高軟件結構的設計水平征绸。
1:單一指責原則(SRP:Simple Responsibility Principle)
一個類只負責一個功能領域的相應職責久橙。
在使用該原則來進行軟件設計的時候一定要注意,不要讓類的承擔過多的職能管怠,承擔的職能越多淆衷,功能模塊間的耦合性越強,維護成本也就越高排惨,而且這個類被復用的可能性就越小吭敢。我們要將不同類型的職責拆分開來,分別封裝到不同的類中暮芭,來實現(xiàn)職責的單一化鹿驼。
2:開閉原則(OCP:Open-Close Principle)
軟件實體對擴展開放欲低,對修改關閉。軟件實體應當在不修改源代碼的情況下對功能進行擴展畜晰。
在軟件開發(fā)中砾莱,我們不得不面臨一個問題,那就是軟件的需求會隨著時間的推移而不斷的變化凄鼻,這時候一個可擴展性強腊瑟,靈活度高的軟件系統(tǒng)就顯的十分必要了。要滿足這樣要求的系統(tǒng)块蚌,必須要具備一些基本特定闰非。如果一個軟件系統(tǒng)符合開閉原則,那么這個系統(tǒng)就可以很好的滿足擴展性峭范,靈活性的需求财松。
而在實現(xiàn)開閉原則的過程中。抽象化的設計是重中之重纱控,抽象化才是開閉原則的關鍵辆毡,在Java中我們可以利用接口或抽象類來構建一個抽象層,而將具體的實現(xiàn)行為移至實現(xiàn)層完成甜害。當需要修改系統(tǒng)的行為時舶掖,我們不需要修改抽象層,只需要新增新的具體類來實現(xiàn)新的業(yè)務邏輯就可以了尔店。這樣我們就可以在不修改源代碼的基礎上實現(xiàn)新的功能眨攘,滿足開閉原則的要求。
3:里氏代換原則(LSP:Liskov Substitution Principle)
所有引用基類對象的地方能夠透明地使用其子類的對象闹获。
如果對每一個類型為T1的對象o1期犬,都有類型為T2的對象o2,使得以T1定義的所有程序P在所有的對象o1都替換成o2時避诽,程序P的行為沒有變化龟虎,那么類型T2是類型T1的子類型。
換言之沙庐,一個軟件實體如果使用的是一個基類的話鲤妥,那么一定適用于其子類,而且它根本不能察覺出基類對象和子類對象的區(qū)別拱雏。
比如棉安,假設有兩個類,一個是Base類铸抑,另一個是Child類贡耽,并且Child類是Base的子類。那么一個方法如果可以接受一個基類對象b的話:method1(Base b)那么它必然可以接受一個子類的對象method1(Child c).
注意事項
- 為了保證軟件系統(tǒng)的擴展性,子類要重寫父類中所有的方法蒲赂。若在子類中存在父類中沒有的特有方法阱冶,那么通過父類則無法調用該方法。
- 在運用里氏代換原則時候滥嘴,父類盡量設計成接口或者抽象類木蹬,子類繼承父類或者父接口,實現(xiàn)父類中聲明的方法若皱,在運行時镊叁,子類實例替代父類實例。這樣就可以很方便的擴展系統(tǒng)的功能走触,
- Java語言中晦譬,在編譯階段,Java編譯器會檢查一個程序是否符合里氏代換原則饺汹,這是一個與實現(xiàn)無關的蛔添、純語法意義上的檢查痰催,但Java編譯器的檢查是有局限的兜辞。
4:依賴倒轉原則(DIP:Dependence Inversion Principle)
抽象不應該依賴于細節(jié),細節(jié)應該依賴于抽象夸溶。換句話說逸吵,要針對接口編程,而不是針對實現(xiàn)編程缝裁。
根據(jù)依賴倒置原則扫皱,我們應當盡量使用抽象類或接口來定義成員變量,參數(shù)類型捷绑,返回值類型韩脑,不要使用具體的實現(xiàn)類來做這些事情,
為了保證依賴倒置原則的良好應用粹污,具體類應該只實現(xiàn)抽象層的方法段多,不要給出多余的方法,抽象類無法調用具體類中特有的方法壮吩。
在實現(xiàn)依賴倒轉原則時进苍,我們需要針對抽象層編程,而將具體類的對象通過依賴注入(DependencyInjection, DI)的方式注入到其他對象中鸭叙,依賴注入是指當一個對象要與其他對象發(fā)生依賴關系時觉啊,通過抽象來注入所依賴的對象。
5:接口隔離原則(ISP:Interface Segregation Principle)
使用多個專門的接口沈贝,而不使用單一的總接口杠人。客戶端不應該依賴那些不需要的接口。每一種接口應該承擔相對獨立的功能嗡善,不該干的不要干市俊,自己該干的就要干好。
其中的接口有兩層含義
- 某個類型中所有的方法,是邏輯上的抽象滤奈。
當把“接口”理解成一個類型所提供的所有方法特征的集合的時候摆昧,這就是一種邏輯上的概念,接口的劃分將直接帶來類型的劃分蜒程∩鹉悖可以把接口理解成角色,一個接口只能代表一個角色昭躺,每個角色都有它特定的一個接口忌锯,此時,這個原則可以叫做“角色隔離原則”领炫。 - 具體指代某個編程編程語言偶垮,“接口”的定義。
如果把“接口”理解成狹義的特定語言的接口帝洪,那么ISP表達的意思是指接口僅僅提供客戶端需要的行為似舵,客戶端不需要的行為則隱藏起來,應當為客戶端提供盡可能小的單獨的接口葱峡,而不要提供大的總接口砚哗。在面向對象編程語言中,實現(xiàn)一個接口就需要實現(xiàn)該接口中定義的所有方法砰奕,因此大的總接口使用起來不一定很方便蛛芥,為了使接口的職責單一,需要將大接口中的方法根據(jù)其職責不同分別放在不同的小接口中军援,以確保每個接口使用起來都較為方便仅淑,并都承擔某一單一角色。接口應該盡量細化胸哥,同時接口中的方法應該盡量少涯竟,每個接口中只包含一個客戶端(如子模塊或業(yè)務邏輯類)所需的方法即可,這種機制也稱為“定制服務”烘嘱,即為不同的客戶端提供寬窄不同的接口昆禽。
在使用接口隔離原則時,我們需要注意控制接口的粒度蝇庭,接口不能太小醉鳖,如果太小會導致系統(tǒng)中接口泛濫,不利于維護哮内;接口也不能太大盗棵,太大的接口將違背接口隔離原則壮韭,靈活性較差,使用起來很不方便纹因。一般而言喷屋,接口中僅包含為某一類用戶定制的方法即可,不應該強迫客戶依賴于那些它們不用的方法瞭恰。
6:合成復用原則(CRP:Composite Reuse Principle)
盡量使用對象組合屯曹,而不是繼承來達到復用的目的。
一個對象通過關聯(lián)關系來引入其他已有的對象惊畏,通過委派調用已有對象中的方法恶耽,來實現(xiàn)復用功能的目的。
通常來說颜启,如果兩個類之間是“Has-A”的關系應使用組合或聚合偷俭,如果是“Is-A”關系可使用繼承。"Is-A"是嚴格的分類學意義上的定義缰盏,意思是一個類是另一個類的"一種"涌萤;而"Has-A"則不同,它表示某一個角色具有某一項責任口猜。
7:迪米特法則(LoD:Law of Demeter)
一個軟件實體應當盡可能少地與其他實體發(fā)生相互作用负溪。
迪米特法則要求,當系統(tǒng)中的一個模塊發(fā)生變更時暮的,應該盡可能少的影響其他模塊笙以,那樣系統(tǒng)的擴展會比較容易。迪米特原則可以降低系統(tǒng)的耦合程度冻辩,使類與類之間保持一種松耦合的關系。
迪米特原則要求我們“不要跟陌生人交談拆祈,只跟熟人打交道”恨闪,以下條件就是我們需要打交道的熟人。
- 當前對象this放坏。
- 對象中方法的形式參數(shù)咙咽。
- 對象中映入的成員對象。
- 如果成員對象是集合淤年,那么集合中的元素也是我們的熟人钧敞。
- 當前對象中創(chuàng)建的其他對象。
迪米特法則要求我們在設計系統(tǒng)時麸粮,應該盡量減少對象之間的交互溉苛,如果兩個對象之間不必彼此直接通信,那么這兩個對象就不應當發(fā)生任何直接的相互作用弄诲,如果其中的一個對象需要調用另一個對象的某一個方法的話吼句,可以通過第三者轉發(fā)這個調用。簡言之性湿,就是通過引入一個合理的第三者來降低現(xiàn)有對象之間的耦合度澳骤。
在將迪米特法則運用到系統(tǒng)設計中時,要注意下面的幾點:在類的劃分上滴肿,應當盡量創(chuàng)建松耦合的類,類之間的耦合度越低,就越有利于復用想许,一個處在松耦合中的類一旦被修改,不會對關聯(lián)的類造成太大波及断序;在類的結構設計上伸刃,每一個類都應當盡量降低其成員變量和成員函數(shù)的訪問權限;在類的設計上逢倍,只要有可能捧颅,一個類型應當設計成不變類;在對其他類的引用上较雕,一個對象對其他對象的引用應當降到最低碉哑。