天天看點

設計模式--面向對象程式設計的六大設計原則

開篇

新工作主要是做android系統應用層的開發維護, 是以閱讀大量源代碼就是日常了,閱讀過程中,深深的感受到了有必要再複習一遍設計模式,以便于吸收Google那龐大的精華~

也越來越覺得做好學習筆記是一件很重要的事情,把學了的東西寫成部落格來記錄,也是一件很有趣的事情,這篇就是接下來學習設計模式的第一篇筆記。

面向對象程式設計的六大設計原則(SOLID)

面向對象程式設計的六大設計原則有:單一職責原則、開放封閉原則、裡氏替換原則、依賴倒轉原則、接口隔離原則、迪米特法則,下面将一一介紹。

單一職責原則(SPR:Single Responsibility Principle)

單一職責原則:就一個類而言,應該僅有一個引起它變化的原因, 或者說一個類隻負責一個功能領域中的相應職責。

比如我們常用的ListView來展示資料, Listview負責顯示, Adapter用來加載資料, 各自負責各自的功能, 以達到高内聚、低耦合的代碼結構。

總之,一個類不能有太多的功能, 否則就需要考慮将這個類得多重職能一一拆解。這是最簡單但又最難運用的原則,需要有較強的分析設計能力和相關實踐經驗。

開放封閉原則(OCP:Open-Closed Principle)

開放封閉原則,是指軟體實體(類、子產品、函數等)應該可以擴充,但是不可修改。大白話就是盡量在不修改原有代碼下去進行擴充。

作為開發者,我們深知需求都是會随着時間推移而變化的, 而面對新的需求, 我們又要保證系統的設計架構是穩定的,不能為了一個需求就把以前的架構推翻重來, 那樣的話,成本就太大了。

抽象化是開放封閉原則的關鍵, 是以, 我們在設計代碼的時候,要充分考慮,哪些是不易變的, 哪些是很可能變化的,然後将變化的部分通過抽象來隔離變化,進而實作無須對抽象層進行修改,隻需要在具體類在抽象中去實作新的功能即可。我們可以通過抽象類或者某個抽象方法,讓變化的部分在子類去實作,以達到子類的不同需求。

實際開發中,有些代碼在編寫時,我們也不知道未來會不會變化, 我們隻有通過經驗猜測,或者當遇到需要變化的情況是, 這是就需要去建立抽象來隔離以後類似的變化了。

比如,剛開始時, 我們隻會做加法運算, 我們就寫了一個加法類, 但是後來,我們又學會了減法、乘法、除法等,這時,我們就可以抽象為一個運算類,裡面有一個運算的方法, 但是具體怎麼運算,就交給子類去具體實作, 進而達到了開放封閉原則。即抽象的運算類就不用去修改,達到了封閉的原則,而運算方法的具體實作就交給子類, 達到了開放的原則。

裡氏替換原則(LSP:Liskov Substitution Principle)

裡氏替換原則:子類必須能替換它的父類。即所有引用父類的地方,都可以用一個子類把這個父類替換掉。

例如:List List = new ArrayList();
用子類替換父類即: ArrayList list = new ArrayList();
           

裡氏替換原則通俗的來講就是:子類可以擴充父類的功能,但不能改變父類原有的功能。它包含以下4層含義:

  • 子類可以實作父類的抽象方法,但不能覆寫父類的非抽象方法。
  • 子類中可以增加自己特有的方法。
  • 當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬松。
  • 當子類的方法實作父類的抽象方法時,方法的後置條件(即方法的傳回值)要比父類更嚴格。

接口隔離原則(ISP:Interface Segeration Principle)

接口隔離原則:使用多個專門的接口,而不使用單一的總接口。即用戶端不應該依賴那些它不需要的接口,應該使接口盡量細化而不過于臃腫。

應當為業務提供盡可能小的單獨的接口,而不要提供大的總接口。在面向對象程式設計語言中,實作一個接口就需要實作該接口中定義的所有方法,是以大的總接口使用起來不一定很友善,為了使接口的職責單一,需要将大接口中的方法根據其職責不同分别放在不同的小接口中,以確定每個接口使用起來都較為友善,并都承擔某一單一角色。接口應該盡量細化,同時接口中的方法應該盡量少。

依賴倒轉原則(DIP:Dependency Inversion Principle)

依賴倒轉原則:抽象不應該依賴細節,細節應該依賴抽象。即要針對接口程式設計,而不是實作程式設計。

舉個栗子, 做項目多數都要通路資料庫,是以整個代碼結構中,會包含業務代碼和資料庫通路, 假如我們需求有變,産品經理或者客戶要求使用不同的資料庫或者存儲資訊方式, 如果我們在業務代碼和資料庫通路代碼綁定在一起了, 那就是大災難,需要修改的代碼一大片一大片的。而如果我們将業務代碼和資料庫通路分為兩個子產品,分别進行抽象,有自己的抽象父類或借口,那麼業務代碼調用資料庫時, 通過調用資料庫的抽象父類或者接口的方法, 則不管底層資料庫怎麼變化, 業務代碼都不用管, 因為抽象父類的方法名不會變,隻是具體的實作變了。底層資料庫如果發生變化, 我們要做的事就是在一個子類中去具體實作新的資料庫即可,不會影響業務代碼。

迪米特法則(LoD:Law of Demeter)

迪米特法則,又稱為最小知道原則。即一個軟體實體應當盡可能少地與其他實體發生互相作用。如果兩個對象之間不必彼此直接通信,那麼這兩個對象就不應當發生任何直接的互相作用,如果其中的一個對象需要調用另一個對象的某一個方法的話,可以通過第三者轉發這個調用

如果一個系統符合迪米特法則,那麼當其中某一個子產品發生修改時,就會盡量少地影響其他子產品,擴充會相對容易,這是對軟體實體之間通信的限制,迪米特法則要求限制軟體實體之間通信的寬度和深度。迪米特法則可降低系統的耦合度,使類與類之間保持松散的耦合關系。

迪米特法則要求我們在設計系統時,**應該盡量減少對象之間的互動,如果兩個對象之間不必彼此直接通信,那麼這兩個對象就不應當發生任何直接的互相作用,如果其中的一個對象需要調用另一個對象的某一個方法的話,可以通過第三者轉發這個調用。**簡言之,就是通過引入一個合理的第三者來降低現有對象之間的耦合度。

在将迪米特法則運用到系統設計中時,要注意下面的幾點:在類的劃分上,應當盡量建立松耦合的類,類之間的耦合度越低,就越有利于複用,一個處在松耦合中的類一旦被修改,不會對關聯的類造成太大波及;在類的結構設計上,每一個類都應當盡量降低其成員變量和成員函數的通路權限;在類的設計上,隻要有可能,一個類型應當設計成不變類;在對其他類的引用上,一個對象對其他對象的引用應當降到最低。

下面通過一個簡單執行個體來加深對迪米特法則的了解:

Sunny軟體公司所開發CRM系統包含很多業務操作視窗,在這些視窗中,某些界面控件之間存在複雜的互動關系,一個控件事件的觸發将導緻多個其他界面控件産生響應,例如,當一個按鈕(Button)被單擊時,對應的清單框(List)、組合框(ComboBox)、文本框(TextBox)、文本标簽(Label)等都将發生改變,在初始設計方案中,界面控件之間的互動關系可簡化為如下圖:

設計模式--面向對象程式設計的六大設計原則

在圖1中,由于界面控件之間的互動關系複雜,導緻在該視窗中增加新的界面控件時需要修改與之互動的其他控件的源代碼,系統擴充性較差,也不便于增加和删除新控件。

現使用迪米特對其進行重構。

在本執行個體中,可以通過引入一個專門用于控制界面控件互動的中間類(Mediator)來降低界面控件之間的耦合度。引入中間類之後,界面控件之間不再發生直接引用,而是将請求先轉發給中間類,再由中間類來完成對其他控件的調用。當需要增加或删除新的控件時,隻需修改中間類即可,無須修改新增控件或已有控件的源代碼,重構後結構如圖2所示:

設計模式--面向對象程式設計的六大設計原則

繼續閱讀