物件導向設計原則之里氏代換原則

Liuwei-Sunny發表於2012-05-06

      里氏代換原則由2008年圖靈獎得主、美國第一位電腦科學女博士Barbara Liskov教授和卡內基·梅隆大學Jeannette Wing教授於1994年提出。其嚴格表述如下:如果對每一個型別為S的物件o1,都有型別為T的物件o2,使得以T定義的所有程式P在所有的物件o1代換o2時,程式P的行為沒有變化,那麼型別S是型別T的子型別。這個定義比較拗口且難以理解,因此我們一般使用它的另一個通俗版定義:

里氏代換原則(Liskov Substitution Principle, LSP):所有引用基類(父類)的地方必須能透明地使用其子類的物件。

      里氏代換原則告訴我們,在軟體中將一個基類物件替換成它的子類物件,程式將不會產生任何錯誤和異常,反過來則不成立,如果一個軟體實體使用的是一個子類物件的話,那麼它不一定能夠使用基類物件。例如:我喜歡動物,那我一定喜歡狗,因為狗是動物的子類;但是我喜歡狗,不能據此斷定我喜歡動物,因為我並不喜歡老鼠,雖然它也是動物。

      例如有兩個類,一個類為BaseClass,另一個是SubClass類,並且SubClass類是BaseClass類的子類,那麼一個方法如果可以接受一個BaseClass型別的基類物件base的話,如:method1(base),那麼它必然可以接受一個BaseClass型別的子類物件submethod1(sub)能夠正常執行。反過來的代換不成立,如一個方法method2接受BaseClass型別的子類物件sub為引數:method2(sub),那麼一般而言不可以有method2(base),除非是過載方法。

      里氏代換原則是實現開閉原則的重要方式之一,由於使用基類物件的地方都可以使用子類物件,因此在程式中儘量使用基類型別來對物件進行定義,而在執行時再確定其子類型別,用子類物件來替換父類物件

      在使用里氏代換原則時需要注意如下幾個問題:

      (1)子類的所有方法必須在父類中宣告,或子類必須實現父類中宣告的所有方法。根據里氏代換原則,為了保證系統的擴充套件性,在程式中通常使用父類來進行定義,如果一個方法只存在子類中,在父類中不提供相應的宣告,則無法在以父類定義的物件中使用該方法。

      (2)  我們在運用里氏代換原則時,儘量把父類設計為抽象類或者介面,讓子類繼承父類或實現父介面,並實現在父類中宣告的方法,執行時,子類例項替換父類例項,我們可以很方便地擴充套件系統的功能,同時無須修改原有子類的程式碼,增加新的功能可以通過增加一個新的子類來實現。里氏代換原則是開閉原則的具體實現手段之一。

      (3) Java語言中,在編譯階段,Java編譯器會檢查一個程式是否符合里氏代換原則,這是一個與實現無關的、純語法意義上的檢查,但Java編譯器的檢查是有侷限的。

      在Sunny軟體公司開發的CRM系統中,客戶(Customer)可以分為VIP客戶(VIPCustomer)和普通客戶(CommonCustomer)兩類,系統需要提供一個傳送Email的功能,原始設計方案如圖1所示:

1原始結構圖

      在對系統進行進一步分析後發現,無論是普通客戶還是VIP客戶,傳送郵件的過程都是相同的,也就是說兩個send()方法中的程式碼重複,而且在本系統中還將增加新型別的客戶。為了讓系統具有更好的擴充套件性,同時減少程式碼重複,使用里氏代換原則對其進行重構。

      在本例項中,可以考慮增加一個新的抽象客戶類Customer,而將CommonCustomerVIPCustomer類作為其子類,郵件傳送類EmailSender類針對抽象客戶類Customer程式設計,根據里氏代換原則,能夠接受基類物件的地方必然能夠接受子類物件,因此將EmailSender中的send()方法的引數型別改為Customer,如果需要增加新型別的客戶,只需將其作為Customer類的子類即可。重構後的結構如圖2所示:

圖2  重構後的結構圖

      里氏代換原則是實現開閉原則的重要方式之一。在本例項中,在傳遞引數時使用基類物件,除此以外,在定義成員變數、定義區域性變數、確定方法返回型別時都可使用里氏代換原則。針對基類程式設計,在程式執行時再確定具體子類。

擴充套件

里氏代換原則以Barbara Liskov(芭芭拉·利斯科夫)教授的姓氏命名。芭芭拉·利斯科夫:美國電腦科學家,2008年圖靈獎得主,2004年約翰·馮諾依曼獎得主,美國工程院院士,美國藝術與科學院院士,美國計算機協會會士,麻省理工學院電子電氣與電腦科學系教授,美國第一位電腦科學女博士。

 

 【作者:劉偉  http://blog.csdn.net/lovelion

相關文章