Liskov替換原則

Liskov替換原則(Liskov Substitution Principle,LSP):
     是一組用於創建繼承層次結構的指導原則,按照Liskov替換原則創建的繼承層次結構中,客戶端代碼能夠放心的使用他的任意類或子類而不擔心影響所期望的行爲。
      (如果S是T的子類型,那麼所有T類型的對象都可以在不破壞程序的情況下被S類型替換)


契約:
      前置條件(precondition):一個能保證方法穩定無錯運行的先決條件。所有方法在被調用前要求某些前置條件爲真。(添加防衛語句判斷參數是否有效)。所有的前置條件檢查的狀
態必須是公開訪問的。(客戶端無法保證私有狀態有效。)
      後置條件(postcondition):在方法退出是檢查一個對象是否處於無效狀態。與實現前置條件一樣,可以使用防衛語句實現後置條件。
       數據不變式(data invariant):是在一個對象生命週期內始終都保持爲真的一個謂詞。該謂詞條件在從構造後一直到超出其作用範圍前這段時間內都爲真。(即將防衛語句添加到構造
函數中或者屬性設置器中,從客戶端傳入的成員變量永遠有效)。
       封裝與契約:可以將傳入的參數封裝爲一個類,在類中對變量進行契約設置。
       Lisov契約規則:1.子類型不能加強前置條件;2.子類型不能削弱後置條件;3.子類型必須保持超類型中的數據不變式。Liskov替換原則明確規定了繼承時一些變更是被禁止的,因爲
他們會導致原有的使用超類實例的已有客戶端代碼在切換子類時必須要做更改。
               1.前置條件不能被加強:當子類重寫包含前置條件的超類方法時,不應該加強現有的前置條件。這樣做很可能會影響到那些已經假設超類的所有方法定義了最嚴格的前置條件
契約的客戶端代碼。(如果子類增強了前置條件,創建超類引用時,原有的超類契約變得無效化。客戶端需要判斷類類型,這樣增加了類與客戶端的耦合性)
               2.後置條件不能被削弱:已有的客戶端代碼在原有的超類切換至新的子類時可能會出錯。(如果嚴格遵守Liskov替換原則,你所創建的所有子類都能夠被所有已有的客戶端代
碼使用且不會出現意料之外的錯誤)例:如果超類後置條件設置函數範圍值大於0,客戶端按照遵循這個契約。但是當某個子類弱化後置條件,使得返回值可以等於0,那麼前面客戶端遵循的
契約將會一直報錯。需要修改客戶端的代碼。
               3.數據不變式必須被保持:創建新的子類時,必須繼續遵守基類中的所有數據不變式。因爲子類有很多機會來改變基類中的私有數據。
       代碼契約:引用system.Diagnostics.Conracts命名空間後,使用Contract靜態類中提供的實現契約的主要功能。(注:如果使用這種代碼契約方式,代碼中的許多位置都有這個靜態
類,如果想要刪除,工作量有些大。所以要是想使用,則全部位置都使用)


協變和逆變:
         1、協變(covariance):在使用泛型參數的時候,ICovariant<out T>泛型參數T使用基類類型,但是當傳入對象爲子類類型時也同樣有效,這樣的效果是由協變和多態的緊密配合
。(繼承是不具備協變的能力)。在設計接口的時候,如果需要使用協變的能力,建議在設計接口的時候添加泛型參數來設置返回類型,因爲泛型支持協變。
         2、逆變(contravariance):逆變是一個類似協變的概念。協變只是與方法的返回類型的處理相關,而逆變是與方法參數類型的處理相關。IContravariant<in T>接口定義的方法只接受由泛型參數指定類型的單個參數。
         3、不變性(data invariant):如果泛型參數沒有設置in out關鍵字,那麼這個類型是不變體,不支持協變、逆變。(只有在設計泛型時殘能將類型定義爲可協變的或可逆變的)
Liskov類型系統規則:
         1、子類型的方法參數必須是可逆變的
         2、子類型的返回類型必須是可協變的
         3、不允許引發新的異常(每個接口都應該有一個統一的基礎異常類型,他可以將必要的錯誤信息從異常彙報器傳給異常處理器)
       (只有方法參數支持逆變而且返回類型支持協變,纔可以編寫出遵循Liskov替換原則的代碼)
         

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章