面向對象設計原則

一個良好的面向對象設計需要遵循一些基本原則,如單一職責原則(SRP)、開放-封閉原則(OCP)、Liskov替代原則(LSP)、依賴倒置原則(DIP)、接口分離原則(ISP)等。  

1、 單一職責原則(SRP)   

描述:就一個類而言,應該僅有一個引起它變化的原因。  
應用:在構造對象時,將對象的不同職責分離至兩個或多個類中,確保引起該類變化的原因只有一個。  
帶來的好處:提高內聚、降低耦合。  

個人觀點:該原則可以有效降低耦合,減少對不必要資源的引用。但後果是造成源文件增多,給管理帶來不便,所以在實際應用中,可以對經常使用或經常需要改動的模塊應用該原則。  

2、 開放-封閉原則(OCP)   

描述:"對於擴展是開放的"(Open for extension)。這意味着模塊的行爲是可以擴展的。當應用的需求改變時,可以對模塊進行擴展,使其具有滿足改變的新行爲。也就是說,我們可以改變模塊的功能。"對於更改是封閉的"(Close for modification)。對模塊行爲進行擴展時,不必改動模塊的源代碼或者二進制代碼。  應用:高級語言中的接口與虛擬類。  
帶來的好處:提高靈活性、可重用性、可維護性。  
個人觀點:OCP的關鍵是抽象,抽象的目的是創建一個固定卻能夠描述一組任意個可能行爲的基類。而這一組可能的行爲則表現爲派生類。對於基類的更改是封閉的,所以它裏邊的方法一旦確定就不能更改(對接口裏的方法進行更改將帶來災難性的後果)。模塊通過抽象基類進行引用,對派生類的擴展並不影響整個模塊,所以它是開放的。遵循OCP的代價也是昂貴的,創建正確的抽象是要花費開發時間和精力的,同時抽象也增加了軟件設計的複雜性。因此有效的預知變化是OCP設計的要點,這需要我們進行適當的調查,提出正確的問題,並利用我們的經驗和一般常識來做出判斷。正確的做法是,只對程序中頻繁變化的部分做出抽象,拒絕不成熟的抽象和抽象本身一樣重要。  
3、 Liskov替代原則(LSP)   
描述:若對每個類型S的對象O1,都存在一個類型T的對象O2,使得在所有針對T編寫的程序P中,用O1替代O2後,程序P行爲功能不變,則S是T的子類型。  
應用:在實現繼承時,子類型(subtype)必須能替代掉它們的基類型(base type)。如果一個軟件實體使用的是基類的話那麼也一定適用於子類。但反過來的代換不成立。  

個人觀點: LSP是使OCP成爲可能的主要原則之一,對LSP的違反將導致對OCP的違反,同時二者是OOD中抽象和多態的理論基礎,在OOPL中表現爲繼承。在高級語言(JAVA、C#)中,只要我們嚴格按照接口和虛擬類的語法規範來做就能很好遵循此原則,另外我們還應該避免一些更微妙的違規情況。舉個例子,正方形和矩形,矩形可以做爲正方形的基類,因爲正方形也是一種矩形,但對於正方形來說,setWidth()和setHeight()是冗餘的,且容易引起錯誤,這樣的設計就違反了LSP原則。如果有兩個具體類A和B之間的關係違反了LSP,可以在以下兩種重構方案中選擇一種:1 .創建一個新的抽象類C,作爲兩個具體類的超類,將A和B共同的行爲移動到C中,從而解決A和B行爲不完全一致的問題。 2 .從B到A的繼承關係改寫爲委派關係。 

 4、 依賴倒置原則(DIP)   

描述:A .高層模塊不應該依賴於低層模塊。二者都應該依賴於抽象。B .抽象不應該依賴於細節。細節應該依賴於抽象。  
應用:要依賴抽象,不要依賴於具體。即針對接口編程,不要針對實現編程。針對接口編程的意思是,應當使用接口和抽象類進行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數據類型的轉換等。不要針對實現編程的意思就是說,不應當使用具體類進行變量的類型聲明、參量的類型聲明,方法的返還類型聲明,以及數據類型的轉換等。  

結論:DIP雖然強大,但卻不易實現,因爲依賴倒轉的緣故,對象的創建很可能要使用對象工廠,以避免對具體類的直接引用,此原則的使用將導致大量的類文件。給維護帶來不必要的麻煩。所以,正確的做法是隻對程序中頻繁變化的部分進行依賴倒置。


  5、 接口隔離原則(ISP)   

描述:不要強迫客戶依賴於它們不用的方法。  

應用:一個類對另外一個類的依賴性應當是建立在最小的接口上的。如果客戶端只需要某一些方法的話,那麼就應當向客戶端提供這些需要的方法,而不要提供不需要的方法。提供接口意味着向客戶端作出承諾,過多的承諾會給系統的維護造成不必要的負擔。  結論:使用多個專門的接口比使用單一的接口要好。  


6、總結  

遵循以上原則,可以使我們的軟件更具靈活性,強壯性。但靈活是需要付出代價的,由多態帶來的性能損失就是最明顯的一個問題。所以我們需要權衡,需要做出選擇,在靈活與性能之間做出選擇。  
追本溯源,促使我們使用這些原則的原因是爲了滿足需求的變更,於是需求分析就顯得格外重要。然而不管怎麼充分的需求分析都可能遭遇需求變更,於是預測變化就成了一個讓人頭痛的事。還是讓我們來看看敏捷設計(XP)是怎麼解決這些問題的:"敏捷開發人員不會對一個龐大的預先設計應用那些原則和模式,相反,這些原則和模式被應用在一次次的迭代中,力圖使代碼以及代碼所表達的設計保持乾淨。"也就是說敏捷設計通過快速的迭代來刺激變化,讓這些變化及早暴露,再根據變化進行相應改動。很明顯這要比一次性完整設計輕鬆容易的多。  
軟件開發的全部藝術就是權衡:在簡單與複雜之間權衡,在一種方案與另一種方案之間權衡。如果把每個問題、每個權衡的利弊都考慮得清清楚楚,恐怕開發一個應用程序的成本會高得驚人。所以,很多時候我們更依賴自己的審美眼光,用平靜的心去設計一個賞心悅目的系統。
發佈了20 篇原創文章 · 獲贊 8 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章