天天看點

軟體設計 軟體設計模式之SOLID原則

軟體設計模式之SOLID原則

By:授客 QQ:1033553122

#單一職責原則(SRP)

定義:任何一個軟體子產品都隻對某一類行為者負責

說明:這裡“軟體子產品”,在大部分情況下,可以簡單定義為一個源代碼檔案、一個類、一組緊密相關的函數和資料結構、

#開閉原則(OCP)

定義:軟體實體應當對擴充開放,對修改關閉

說明:這裡的“軟體實體”包含子產品,類,接口,方法等

開閉原意在告訴我們,當應用的需求改變時,在不修改軟體實體原有的源代碼或者二進制代碼的前提下,可以通過新增代碼來滿足新的需求,也就是說一個設計良好的計算機系統應該在不需要修改的前提下就可以輕易被擴充,這是架構的根本目的,如果對原始需求的小小延伸就需要對原有的軟體系統進行大幅修改,那麼這個系統的架構設計顯然是失敗的。

在Java、C++這類語言中,可以通過“抽象限制、封裝變化”來實作開閉原則,即通過接口或者抽象類為軟體實體定義一個相對穩定的抽象層,而将相同的可變因素封裝在相同的具體實作類中。 因為抽象靈活性好,适應性廣,隻要抽象的合理,可以基本保持軟體架構的穩定。而軟體中易變的細節可以從抽象派生來的實作類來進行擴充,當軟體需要發生變化時,隻需要根據需求重新派生一個實作類來擴充就可以了。

而在python中一切都是對象,可以指向任何類型,是以,不用定義接口變可實作類似接口。

#裡氏替換原則(LSP)

第一種定義:如果對每一個類型為S的對象o1,都有類型為T的對象o2,使得以T定義的所有程式P在所有的對象o1都代換成o2 時,程式P的行為沒有發生變化,那麼類型 S 是類型 T 的子類型。

第二種定義:所有引用基類的地方必須能透明地使用其子類的對象。

第一種定義是最正宗的定義,而第二種定義則是最清晰明确的,通俗點講,隻要父類能出現的地方子類就可以出現,而且替換為子類也不會 産生任何錯誤或異常,使用者可能根本就不需要知道是父類還是子類。但是,反過來就不行了,有子類出現的地方,父類未必就能适應

裡氏替換原則是繼承複用的基石,隻有當衍生類可以替換基類,軟體機關的功能不受到影響時,即基類随便怎麼改動子類都不受此影響,那麼基類才能真正被複用

因為繼承帶來的侵入性,增加了耦合性,也降低了代碼靈活性,父類修改代碼,子類也會受到影響,要讓程式遵守裡氏替換原則,實作繼承時必須遵守以下幾點:

1)子類必須實作父類的抽象方法,但不得重寫(覆寫)父類的非抽象(已實作)方法。

2)當子類覆寫或實作父類的方法時,方法的的形參要比父類方法的輸入參數更寬松。

3)當子類的方法實作父類的抽象方法時,方法的傳回值要比父類更嚴格。

4)遵守以上幾點的情況下,無法滿足需求時,可以考慮在子類中增加自己特有的方法。

#接口隔離原則(ISP)

定義:

1、用戶端不應該依賴它不需用的接口

2、類間的依賴關系應該建立在最小的接口上。

簡單了解就是,不要在一個接口裡面放很多的方法,這樣會顯得這個類很臃腫,java接口類為例,繼承接口的非抽象子類,都要實作接口類的擁有的所有方法,是以,當這些子類僅需要要接口類中的部分方法時還是需要去實作對其沒有意義的接口方法,是以,接口應該盡量細化,一個接口對應一個功能子產品,同時接口裡面的方法應該盡可能的少,使接口更加靈活輕便。但是需要注意的是:拆分要适度度。對接口進行細化可以提高程式設計靈活性是不掙的事實,但是如果過小,則會造成接口數量過多,使設計複雜化。是以一定要适度。

接口隔離原則和單一職責原則雖然很類似,但是兩個原則還是存在着明顯的差別。單一職責原則是在業務邏輯上的劃分,注重的是職責。接口隔離原則是基于接口設計考慮。

#依賴反轉原則(DIP)

依賴反轉原則被稱作依賴倒置原則,

1)高層政策性的代碼不應該依賴實作底層細節的代碼

2)抽象不應該依賴于細節,細節應該依賴于抽象

說明:

1、什麼是“高層”,什麼是“細節”?

對一個系統來說,業務邏輯是高層,其他是細節。業務邏輯是僅僅包括用例、業務實體部分,不包括任何架構、存儲(資料庫)、其他系統等部分,是純粹的。其他細節,包括架構、資料庫、消息隊列,都是細節。業務邏輯應該不依賴任何細節。細節的實作可以任意替換而不影響業務邏輯。

依賴倒轉原則是基于這樣的設計理念:相對于細節的多變性,抽象的東西要穩定的多。以抽象為基礎搭建的架構比以細節為基礎的架構要穩定得多,其中心思想是面向接口程式設計

該原則告訴我們,如果想要設計一個靈活的系統,在源代碼層次的依賴關系中就應該多引用穩定的抽象類型,而非具體實作,特别注意不要在具體實作類上建立衍生類,不要覆寫包含具體實作的函數。Java中,抽象多指的是接口或抽象類,用接口或抽象類的目的是制定好規範,而不涉及任何具體的操作,把展現細節的任務交給他們的實作類去完成。

顯而易見,把這條設計原則當成金科玉律來加以嚴格執行是不現實的,因為在實際構造系統的過程中,不可避免的依賴一些具體實作,比如java的String類就是這樣一個具體實作,我們将其強迫的轉化為抽象類是不現實的。類似String類這種本身是非常穩定的類、子產品,可以不用考慮,需要多關注的是經常會變動的具體實作子產品。

在Python中,可以不通過抽象類的方式很輕松的實作依賴反轉

例子:音樂玩具播放器模拟程式,要求可以播放各種動物的聲音。

最開始,這個玩具的要求比較簡單,一開始隻要求播放一種動物聲音,鳥叫聲

Bird.java

publicclass Bird{

publicvoid call(){

System.out.println("bird call");

}

}

ToyPlayer.java

publicclass ToyPlayer{

publicvoid play(Bird bird){ #這裡的入參,引用的是具體的實作類

bird.call();

}

Entry.java

publicclass Entry {

publicstaticvoid main(String[] args){

ToyPlayer player = new ToyPlayer();

Bird bird = new Bird();

player.play(bird);

如上,以上代碼是不符合依賴反轉原則的,播放器類,依賴具體的動物類(實作類),當需求變化時可能無法滿足需求。比如,需要給玩具增加其它動物聲,比如狗叫,這個時候就需要更改程式了。

改進版

Animal.java

interface Animal{

publicvoid call();

publicclass Bird implements Animal{

Dog.java

publicclass Dog implements Animal{

System.out.println("dog call");

publicvoid play(Animal animal){ #注意,這裡替換了參數類型--替換具體類類型 Bird 為抽象類類型 Animal

animal.call();

player.play(bird);

Dog dog = new Dog();

player.play(dog);

作者:授客

QQ:1033553122

全國軟體測試QQ交流群:7156436

Git位址:https://gitee.com/ishouke

友情提示:限于時間倉促,文中可能存在錯誤,歡迎指正、評論!

作者五行缺錢,如果覺得文章對您有幫助,請掃描下邊的二維碼打賞作者,金額随意,您的支援将是我繼續創作的源動力,打賞後如有任何疑問,請聯系我!!!

           微信打賞                       

支付寶打賞                  全國軟體測試交流QQ群  

軟體設計 軟體設計模式之SOLID原則
軟體設計 軟體設計模式之SOLID原則
軟體設計 軟體設計模式之SOLID原則

繼續閱讀