系統設計原則--SRP OCP LSP DIP ISP

一、單一職責原則(SRP)
      每個類應當只負責單一內聚的職責,每一個職責都是變化的一個軸線,當需求變化時,該變化會反映爲類的職責的變化。一個類應當僅有一個引起它變化的原因,如果一個類承擔了多於一個的職責,那麼引起它變化的原因就會有多個,等於把這些職責耦合在了一起。違反SRP的設計通常可以採用門面模式或代理模式進行重構,分離業務的職責。
二、開閉原則(OCP)
      軟件實體(類、包、模塊等)應該是可以擴展的,但是不可修改的,即對於擴展是開放的,對於修改是封閉的,對實體的行爲擴展時,無需改動源代碼或二進制代碼,即開閉原則(The Open-Closed Principle)。開閉原則的關鍵是抽象設計,對於完全的OCP是不可能的,應當對最有可能、最經常的變化進行抽象,遵循開閉原則,拒絕不成熟的抽象和抽象本身一樣重要。
三、Liskov替換原則(LSP)LSPLiskov Substitution Principle
      子類型必須能夠完全替換掉它們的基類型。滿足Liskov原則的類型滿足如下性質:若對每個類型S的對象O1,都存在一個類型T的對象O2,使得在所有針對T編寫的程序中,用O1替換掉O2後,程序的行爲功能不變,則S是T的子類型。OOD中IS-A關係是就行爲方式而言的,行爲方式是可以進行合理假設的,是客戶程序所依賴的。模型的有效性只能通過它的客戶程序來體現。一些違反了LSP的繼承設計可以用提取公共部分的方法代替繼承。
四、依賴倒置原則(DIP)Dependence Inversion Principle
      1、高層模塊不應該依賴於低層模塊,二者都應該依賴於抽象;
      每個較高層次都爲它所需要的服務聲明一個抽象接口,較低的層次實現這些抽象接口,每個高層類都通過該抽象接口使用下一層,這樣高層就不依賴於低層,低層反而依賴於高層聲明的抽象服務接口。
      2、抽象不應該依賴於細節,細節應該依賴於抽象;
      程序中所有的依賴關係都應該終止於抽象類或者接口,即:
      任何變量都不應該持有一個指向具體類的指針或引用;
      任何類都不應該從具體類派生;
      任何方法都不應該覆寫它的任何基類中已經實現的方法;
      如果一個具體類不太會改變,並且也不會創建其他類似的派生類,那麼依賴於它不會造成損害。例如:java.lang.String。
五、接口隔離原則(ISP) Interface Segregation Principle
      不應該強迫客戶依賴於它們不用的方法。
      胖接口會導致他們的客戶程序產生不正常並且有害的耦合關係,當一個客戶程序要求該胖接口進行一個改動時,會影響到其他的客戶程序,因此,客戶程序應當僅僅依賴於他們實際調用的方法,通過把胖接口分離爲多個特定的客戶程序的接口,可以實現這個目標。每個特定於客戶程序的接口僅僅聲明它的客戶程序需要調用的方法,實現類實現所有特定於客戶程序的接口,解除這些耦合關係,使客戶程序之間互不依賴。
      分離接口的常用方式包括使用委託分離和使用多重繼承分離。分離接口的關鍵在於對於接口的客戶進行分組。




敏捷開發-面向對象設計的11原則
"你不必嚴格遵守這些原則,違背它們也不會被處以宗教刑罰.
但你應當把這些原則看成警鈴,若違背了其中的一條,那麼警鈴就會響起."
1.SRP單一職責原則[適用於類功能]
  (就一個類而言,應該僅有一個引起它變化的原因.)
  詳細說明:
  如果一個類承擔的職責過多,就等於把這些職責耦合在一起.
  一個職責的變化可能會削弱或者抑制這個類完成其它職責的能力.
  這種耦合會導致脆弱的設計,當變化發生時,設計會遭受到意想不到的破壞.
  結論:
  它是所有類設計原則最簡單的,也是最難正確使用的.
  我們會自然的把職責結合在一起,軟件設計真正要做的內容就是發現職責並把那些職責相互分離.
2.OCP開放-封閉原則[適用於類抽象]
  (軟件實體(類,模塊,函數...)應該是可以擴展的,但是不可以修改.)
  詳細說明:
  OCP=對於擴展是開放的,對於修改是封閉的.
  如果程序中的一處改動就會產生連鎖反應,導致一系列相關模塊的改動,那麼設計就有臭味.
  OCP建議我們如果要對系統進行重構,就只需要添加新的代碼,而不必改動已經正常運行的代碼.
  結論:
  在許多方面,OCP都是面向對象設計的核心.
  尊循它可以帶來巨大的好處(程序的靈活性,可重用性,可維護性).
  在代碼中肆意使用OCP也不是一個好主意.
  正確的做法是:開發人員僅僅對程序中呈現頻繁變化的部分做出抽象!拒絕不成熟的抽象和抽象本身一樣重要!
 
3.LSP Liskov替換原則[適用於類層次]
  (子類型必須能夠替換掉它們的基類型.)
  詳細說明:
  Barbara Liskov在1988年說道:
  Liskov替換性質:若對每個類型S的對象O1,都存在一個類型T的對象O2,
  在所有針對類型T編寫的程序P中,用O1代換O2後,程序P行爲功能不變,則類型S是類型T的子對象.
  結論:
  LSP是使用OCP開放-封閉原則成爲可能的主要原則之一,
  正是子類型的可替換性才能用基類類型(基類引用或者指針)的模塊在無需修改的情況下就可以擴展.
  這種可替換性是開發人員可以隱式依賴的東西.
  因此,如果沒有顯示的強制基類類型的契約,那麼代碼就必須良好並明顯的表達出這一點.
  術語"IS-A"不能作爲子類型的定義,
  子類型的正確定義是"可替換性","可替換性"可以通過顯式或者隱式的(動態綁定必須用基類類型)契約.
 
4.DIP依賴倒置原則[適用於類層次]
  (抽象不應該依賴細節.細節應該依賴抽象.)
  詳細說明:
  a.高層模塊不應該依賴於低層模塊,二者都應該依賴抽象(使用接口或者虛類來連接).
  b.抽象不應該依賴於細節,細節應該依賴於抽象.
  結論:
  使用傳統的過程化程序設計方法所創建出來的依賴關係結構和策略是依賴於細節.
  DIP使得細節和策略都依賴於抽象,並且常常爲客戶定製服務接口.
  事實上,這種依賴關係的倒置是好的面向對象的程序設計的標記.
  DIP正確應用對於可重用框架是必須的,對於構建在變化面前富有彈性的代碼也是非常重要的.
  由於抽象和細節被DIP彼此隔離,所以代碼也非常容易維護.

5.ISP接口隔離原則[適用於類的接口]
  不應該強迫客戶程序依賴於它們不用的方法.
  接口屬於客戶,不屬於它所在的類層次結構.
  詳細說明:
  分離客戶就是分離接口.分離接口有2種方法:委託和多重繼承
  接口隔離原則是用來處理胖接口所具有的缺點.
  如果類接口不是內聚的,就表示該類的接口是胖的,需要減肥.
  減肥的原則是接口分成多組方法,每一組方法都服務於一組不同的客戶程序!
  客戶程序面對的就是多個具有內聚接口的抽象基類.
  結論:
  胖類會導致它們的客戶程序之間產生不正常的有害的耦合關係.
  當客戶程序要求胖類進行一個改動時,會影響到所有其它戶程序.
  因此,程序應該僅僅依賴於它們實際調用的方法.
  通過把胖類的接口分解爲多個特定的客戶程序的接口,可以實現這個目標.
  每個特定於客戶程序的接口僅僅聲明它自己調用的函數.
  解除了類的客戶程序之間依賴關係,使它們互不依賴.
 
 
6.REP重用發佈等價原則[適用於包]
  (重用的粒度就是發佈的粒度)
  詳細說明:
  當你重用別人一個類庫時,你的期望是什麼?
  當然是好的文檔,可以工作的代碼,規格清晰的接口!
  你希望作者會一直維護類庫代碼,當作者都把類庫的接口和功能進行任何改變時,你希望得到通知.
  代碼的作者把它們的軟件組織到一個包中(dll,jar,...),所以我們重用的粒度就是包的發佈粒度.
  結論: 
  一個包的重用粒度和和發佈粒度一樣大,由於重用性是基於包的,所以可重用的包必須包含可重用的類.
 
7.CCP共同封閉原則[適用於包]
  (包中的所有類對於同一類性質的變化應該是共同封閉的.
  一個變化若對一個包產生影響,則將對該包中的所有類產生影響,而對於其它包不造成任何影響.)
  詳細說明:
  這是SRP單一職責原則對包的重新規定.這規定了一個包不應該包含多個引用包變化的原因.
  在大多數應用中,可維護性超過可重用性.
  代碼更改:如果代碼要更改,原意更改都集中在一個包中,而不是分佈於多個包中.
  代碼發佈:我們也只發布更改中的包!
  結論:   
  CCP鼓勵我們把可以由於同樣的原因而更改的所有類共同聚集在同一個包中.
8.CRP共同重用原則[適用於包]
  (一個包中的所有類應該是共同重用的.
  如果重用了包中的一個類,那麼就要重用包中的所有類.)
  詳細說明:
  一個包中的所有類應該是共同重用的.
  結論:   
  如果重用了包中的一個類,那麼就要重用包中的所有類.
  這個原則可以幫助我們決定哪些類應該放進同一個包中.
9.ADP無環依賴原則[適用於包]
  (在包的依賴關係圖中不允許存在環.)
  詳細說明:
  如果開發環境中有許多開發人員都在更改相同的源代碼文件集合的情況,
  因爲有人比你走的晚,且改了你所依賴一些東西(類或者方法),第二天來上班,
  你昨天完成的功能,今天不能正常工作,那麼就會發生"晨後綜合症"!
  針對此問題有兩個解決方案:"每週構建"和"消除依賴環" 
  每週構建:應用於中等規模的項目中,它的工作方式爲:每週1-4,開發人員各自工作在私人的代碼空間,周5-6聯合調試!
  消除依賴環:通過把開發環境劃分成可發佈的包,可以解決依賴環.
  結論:
  解決包之間的依賴環有兩個主要方法:
  1.使用依賴倒置原則,在類和依賴類之前添加一個依賴的接口或者抽象類,解除依賴環.
  2.添加新類,把類和依賴類之間的依賴移到一個新的類,解除依賴環.

10.SDP穩定依賴原則[適用於包]
  (朝着穩定的方向進行依賴.)
  詳細說明:
  設計不是完全固定的,要使設計可維護,某種程序的易變性是必要的.
  使用這個原則,我們可以創建對某些變化類型敏感的包.
  其它的包不要依賴這個要變的包.
  軟件包就可以分爲穩定包和可變包!
  如何識別穩定包和可變包?如果許多其它的包都依賴此包,那麼它就是穩定包,否則就是可變包!
  把包放在不同的位置,它的穩定性是不同的.
  如何計算一個包的不穩定性?(輸入耦合度Ca,輸出耦合度Ce)
  不穩定值=Ce/(Ca+ce),此值越低越穩定!
  結論:
  把可變包不穩定值降低的方法是:爲它加上一個抽象外衣(interface/抽象類),其它包調用抽象外衣!
  可變包爲抽象外衣的實現!

11.SAP穩定抽象原則[適用於包]
  (包的抽象程序應該和其它穩定程序一致.)
  詳細說明:  
  此原則把包的穩定性和抽象性聯繫到一起.
  一個穩定的包應該是抽象的,這樣它的穩定性就不會使其無法擴展;
  一個不穩定的包應該具體的, 這樣它的不穩定性使代碼易於修改.
  結論:
  它指出一個包有時候應該達到部分是可抽象的,部分是不穩定的原則
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章