在面向對象軟體開發過程中,一些有經驗的軟體開發人員通常會採用設計模式來解決一些日常工作中的一些問題。設計模式是前人在軟體開發的過程中總結出來的一些解決問題的方案,並且經受住了時間的考驗和廣大軟體開發人員的不斷驗證。在軟體開發過程中,如果我們合理的使用設計模式可以提高代碼的復用性和可維護性。為了保證引 ...
在面向對象軟體開發過程中,一些有經驗的軟體開發人員通常會採用設計模式來解決一些日常工作中的一些問題。設計模式是前人在軟體開發的過程中總結出來的一些解決問題的方案,並且經受住了時間的考驗和廣大軟體開發人員的不斷驗證。在軟體開發過程中,如果我們合理的使用設計模式可以提高代碼的復用性和可維護性。為了保證引用設計模式的合理性,我們在使用設計模式的時候一定要遵守面向對象設計的六大原則:單一職責原則、里氏替換原則、依賴倒轉原則、介面隔離原則、迪米特法則、開閉原則。設計模式就是通過實現這些原則,來達到代碼復用和增加可維護性的目的的。
下麵分別介紹一下,設計模式的六大原則:
■單一職責原則(Single Responsibility Principle)
定義:單一職責原則規定一個類應該只有一個引起它發生變化的原因,即一個類應該只有一個職責。
概述:如果一個類承擔多個職責,就相當於把這些職責耦合在了一起,如果其中的一個職責發生變化,有可能會影響到其它職責的正常運行。另外多個職責耦合在一起,還會降低類的復用性。在軟體開發過程中,如果想要避免這種現象的發生,就要使程式儘可能的遵守單一職責原則。
問題由來:類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能會導致原本運行正常的職責P2功能發生故障。也就是說職責P1和P2被耦合在了一起。
產生問題的原因:程式設計不合理,或是職責擴散。
◆職責擴散:因為某種原因,某一職責被劃分為了多個粒度更細的職責。
解決問題的方法:在寫程式時遵守單一職責原則,將不同的職責P1和P2分別封裝到不同的類或模塊中。能夠引起職責擴散的原因比較多,所以我們在前期進行程式設計的時候,應儘量的遵守單一職責原則。
遵守單一職責原則能給我們的程式帶來的好處有:
◆讓一個類只負責一項職責,增強類的可讀性,提高系統的可維護性。
◆使我們能夠更容易的寫出符合高內聚低耦合核心思想的程式。
註意事項:過度的遵守單一職責原則也會帶來一些弊端,遵守單一職責原則勢必會造成代碼量的增加。如果過度的使用,會使代碼顯得過於臃腫,當一個類的邏輯比較簡單,類中的方法數量比較少,並且不需要經常改動的時候,我們可以根據情況決定是否遵守單一職責原則。
■里氏轉換原則(Liskov Substitution Principle)
定義:里氏轉換原則規定在程式裡面只要是基類出現的地方,都可以用子類進行替換。
概述:里氏轉換原則描述的是父類和子類之間的關係,只有繼承關係存在時,里氏轉換原則才存在。里氏轉換原則是繼承復用的基礎,只有當子類可以替換掉父類,並且軟體單位的功能不受到任何影響時,父類才可以被覆用。
問題由來:類A有一職責P1,現在需要對類A的職責進行擴展,新增加職責P2, 擴展職責的任務在子類B中完成,則子類B在完成新職責P2的同時,有可能會導致原有職責P1不能正常運行。
解決問題的方法:在繼承時,遵守里氏轉換原則。類B繼承父類A時,除添加完成職責P2 的方法外,儘量不要重寫父類的非抽象方法。
遵守里氏轉換原則能給我們的程式帶來的好處有:
◆子類繼承父類之後,可以增加自己特有的職責方法。
◆可以給面向抽象編程提供基礎,合理的遵守里氏轉換原則可以使我們的程式的穩定性和可擴展性更好。
註意事項:在使用里氏轉換原則時需要註意的地方是,父類中凡是已經實現好的方法,實際上是在設定一系列的規範和契約,雖然它不強制要求所有的子類必須遵守這些契約,但是如果子類對這些非抽象方法任意修改,就會對整個繼承系統造成破壞。通俗的講就是:子類可以擴展父類的功能,但是不能改變父類的原有功能。
■依賴倒置原則(Dependency Inversion Principle)
定義:在程式里高層模塊不應該依賴低層模塊,二者都應該依賴抽象;抽象不應該依賴細節,細節應該依賴抽象。
概述:依賴倒置原則的核心思想是面向抽象編程,它基於這樣一個事實,相對於細節的多變性,抽象的東西要更加的穩定,以抽象為基礎搭建起來的架構比以細節為基礎搭建起來的架構要穩定的多。在C# 中,抽象指的是介面或抽象類,細節就是具體的實現類,使用介面或者是抽象類的目的是制定好規範和契約,而不去涉及任何具體的操作,把展現細節的任務交給它們的實現類去完成。
問題由來:類A直接依賴類B,如果要將類A改為依賴類C,則必須通過修改類A的代碼來達成。這種情況,類A一般是高層模塊,負責複雜的業務邏輯;類B和類C是低層模塊,負責基本的原子操作;假如修改類A,會給程式帶來不必要的風險。
解決問題的方法:讓類A依賴介面I,類B和類C各自實現介面I,類A通過介面I間接和類B或者類C發生聯繫,這樣就可以解決上面的問題。就像在三層架構中,讓業務邏輯層和資料庫連接層通過依賴抽象取得聯繫,這樣我們可以在資料庫連接層隨意切換數據源,而不影響業務邏輯層的正常功能。
遵守依賴倒置原則能給我們的程式帶來的好處有:
遵循依賴倒置原則可以降低類之間的耦合性,提高系統的穩定性,降低因修改程式造成的風險。採用依賴倒置原則給多人並行開髮帶來了極大的便利,參與協作開發的人越多、項目越龐大,採用依賴倒置原則的意義就越大。
註意事項: 在實際編程中,我們一般需要做到,低層模塊儘量都要有抽象類或介面,變數的聲明類型儘量是抽象類或介面,使用繼承時遵循里氏轉換原則。
■介面隔離原則(Interface Segregation Principle)
定義:客戶端不應該依賴它不需要的介面;一個類對另一個類的依賴應該建立在最小的介面上。
概述: 在程式設計中,不要讓類去依賴一個含有它不需要的方法的介面。如果讓一個類依賴了含有它不需要的方法的介面,那麼就面臨著由於這些不需要的方法發生了改變,而給該類帶來的改變。一個類對另一個類的依賴應該建立在最小的介面上。
問題由來:類A通過介面I依賴類B,類C通過介面I依賴類D,如果介面I對於類B和類D來說不是最小介面,則類B和類D必須去實現他們不需要的方法。
解決問題的方法:採用介面隔離原則,將介面I拆分為獨立的幾個介面,類A和類C分別與他們需要的介面建立依賴關係。
遵守依賴倒置原則能給我們的程式帶來的好處有:
這樣避免了建立的介面過於臃腫,使子類中只需要去實現它自身需要的方法。可以提高程式設計的靈活性和介面的可復用性,降低類之間的耦合,避免和不相關的類發生聯繫。
註意事項: 使用介面隔離原則需要註意的地方:介面應儘量的小,但是要有限度,對介面細化可以提高程式設計的靈活性,但是如果介面過小,則會造成介面數量過多,使設計複雜化,所以一定要適度。
■迪米特法則(Law of Demeter)
定義:迪米特法則規定,一個對象應該對其它對象保持最少的瞭解。
概述:迪米特法則又叫最少知道原則,通俗的講,就是一個類對自己依賴的類知道的越少越好。也就是說,對於被依賴的類來說,無論邏輯多麼複雜,都應儘量的將邏輯封裝在類的內部,對外除了提供的public方法,不對外泄露任何信息。迪米特法則還有一個更簡單的定義就是只與直接的朋友通信。
問題由來:類與類之間的關係越密切,耦合度就越大,類之間的相互影響也就越大。
解決問題的方法:遵循迪米特法則,如果兩個類不需要直接通信,那麼這兩個類就不應當發生直接的相互引用。如果其中的一個類需要調用另一個類的某一個方法的話,可以通過一個中間類來調用。
遵守迪米特法則能給我們的程式帶來的好處有:
採用迪米特法則的程式設計可以降低類之間的耦合,由於每個類都減少了對其他類的依賴,因此,很容易使得系統的功能模塊更加的獨立,進而也就減少了類之間的相互依賴關係。
註意事項:使用迪米特法則是為了降低類之間的耦合度,由於每個類都減少了不必要的依賴,因此的確可以降低耦合關係。但是凡事都要有度,雖然可以避免與非直接的類通信,但是要通信,必然會通過一個中間類來發生聯繫。如果過分的使用迪米特法則,就會產生大量的中間類,導致系統複雜度變大。所以在採用迪米特法則時要做好權衡,既要做到結構清晰,又要高內聚低耦合。
■開閉原則(Open Closed Principle)
定義:一個軟體實體如類、模塊或函數應該對擴展開發,對修改關閉。
概述:開閉原則是面向對象設計中最基礎的設計原則,它指導我們如何建立穩定靈活的系統。在實際開發的過程中,如果讓我們在設計階段就羅列出系統所有可能的行為,並把這些行為加入到抽象底層,這種做法是不現實的,也是不可取的。因此在做程式從設計的時候,我們應該接受修改,擁抱變化,使我們的代碼對擴展開放,對修改關閉。只有這樣做才能使我們的程式架構更穩定。
問題由來:在軟體的生命周期內,我們會因為功能的變化或系統的升級等原因需要對軟體原有代碼進行修改。在修改時,可能會給原有代碼帶來嚴重的錯誤,導致我們不得不對整個功能進行重構,並且需要將原有代碼經過重新測試。
解決問題的方法:遵守開閉原則,儘量通過擴展軟體實體的行為來實現變化,而不是修改已有的代碼來實現變化。
遵守開閉原則能給我們的程式帶來的好處有:
◆使模塊具有更好的可復用性:
在軟體完成以後,我們仍然可以對軟體進行擴展,可以通過增加新組件的方式非常靈活的加入新功能。因此,我們的軟體系統就可以通過不斷地增加新組件的方式,來滿足不斷變化的需求。
◆可維護性:
對於已有的軟體系統的組件,特別是它的抽象底層我們不去做修改。這樣,我們就不用擔心軟體系統中原有組件的穩定性。這就使得在變化中,軟體系統有一定的穩定性和延續性。
■總結:
在實際開發過程中,我們不應該刻板的遵守設計模式六大原則,而是應該根據實際情況靈活的應用。只有遵守的合理才能夠設計出可維護性好、復用性高的軟體系統。 通篇沒有代碼展示,似乎不太合理,下麵是我在練習時寫的一個完整的項目,托管在了github(SafetyMS) 上,裡面的程式設計基本上符合了設計模式的六大原則。