OOAD-4 面對對象設計七原則--里氏替換原則

里氏替換原則的定義java

  里氏替換原則(Liskov Substitution Principle,LSP)由麻省理工學院計算機科學實驗室的里斯科夫(Liskov)女士在 1987 年的「面向對象技術的高峯會議」(OOPSLA)上發表的一篇文章《數據抽象和層次》(Data Abstraction and Hierarchy)裏提出來的,她提出:繼承必須確保超類所擁有的性質在子類中仍然成立測試

 

里氏替換原則的做用spa

  里氏替換原則是實現開閉原則的重要方式之一。設計

  它克服了繼承中重寫父類形成的可複用性變差的缺點,由於它推崇,子類能夠新增方法,可是不要去覆蓋父類已經寫好的方法orm

  它是動做正確性的保證,即類的擴展不會給已有的系統引入新的錯誤。下降了代碼出錯的可能性。由於裏式替換原則保證了子類不要去覆蓋父類方法,所以,新增新的子類時。父類定義的東西不會改變。也就是說,進行功能擴展時,原有的代碼不會出錯對象

 

 

裏式替換原則的實現方法blog

  裏式替換原則通俗來說就是:子類能夠擴展父類的功能,但不能改變父類原有的功能。也就是說,子類繼承父類時,除添加新的方法完成新增功能外,儘可能不要重寫父類已經實現的方法。繼承

  若是經過重寫父類的方法來完成新的功能,這樣寫起來雖然簡單,可是整個繼承體系的可複用性會比較差,特別是用多態用的比較頻繁時,程序出錯的機率就會變大。由於子類重寫畢竟覆蓋了父類的功能,當須要使用父類的功能時,就容易致使出錯。並且,里氏替換和多態並不衝突,咱們儘可能在抽象類或者接口來作多態,簡單父類通常只是用來自下而上的封裝公有域。接口

  若是程序違背了裏式替換原則,則繼承類的對象在基類出現的地方會出現運行錯誤。由於子類重寫了方法,那麼本來爲基類的地方就不必定能用子類來代替了ip

 

  下面以「幾維鳥不是鳥」爲例來講明裏氏替換原則。

【例2】里氏替換原則在「幾維鳥不是鳥」實例中的應用。

分析:鳥通常都會飛行,如燕子的飛行速度大概是每小時 120 公里。可是新西蘭的幾維鳥因爲翅膀退化沒法飛行。假如要設計一個實例,計算這兩種鳥飛行 300 公里要花費的時間。顯然,拿燕子來測試這段代碼,結果正確,能計算出所須要的時間;但拿幾維鳥來測試,結果會發生「除零異常」或是「無窮大」,明顯不符合預期,其類圖如圖 1 所示。

「幾維鳥不是鳥」實例的類圖
圖1 「幾維鳥不是鳥」實例的類圖


程序代碼以下:

  1. package principle;
  2. public class LSPtest
  3. {
  4. public static void main(String[] args)
  5. {
  6. Bird bird1=new Swallow();
  7. Bird bird2=new BrownKiwi();
  8. bird1.setSpeed(120);
  9. bird2.setSpeed(120);
  10. System.out.println("若是飛行300千米:");
  11. try
  12. {
  13. System.out.println("燕子將飛行"+bird1.getFlyTime(300)+"小時.");
  14. System.out.println("幾維鳥將飛行"+bird2.getFlyTime(300)+"小時。");
  15. }
  16. catch(Exception err)
  17. {
  18. System.out.println("發生錯誤了!");
  19. }
  20. }
  21. }
  22. //鳥類
  23. class Bird
  24. {
  25. double flySpeed;
  26. public void setSpeed(double speed)
  27. {
  28. flySpeed=speed;
  29. }
  30. public double getFlyTime(double distance)
  31. {
  32. return(distance/flySpeed);
  33. }
  34. }
  35. //燕子類
  36. class Swallow extends Bird{}
  37. //幾維鳥類
  38. class BrownKiwi extends Bird
  39. {
  40. public void setSpeed(double speed)
  41. {
  42. flySpeed=0;
  43. }
  44. }


程序的運行結果以下:

若是飛行300千米:
燕子將飛行2.5小時.
幾維鳥將飛行Infinity小時。


程序運行錯誤的緣由是:幾維鳥類重寫了鳥類的 setSpeed(double speed) 方法,這違背了里氏替換原則。正確的作法是:取消幾維鳥原來的繼承關係,定義鳥和幾維鳥的更通常的父類,如動物類,它們都有奔跑的能力。幾維鳥的飛行速度雖然爲 0,但奔跑速度不爲 0,能夠計算出其奔跑 300 公里所要花費的時間。其類圖如圖 2 所示。

「幾維鳥是動物」實例的類圖
圖2 「幾維鳥是動物」實例的類圖
 
  
 
 
里氏替換原則和多態之間的關係
  在第一眼看到里氏替換原則時,我就產生了困惑。爲何要去禁止子類重寫父類方法呢。這不是java多態的基本嗎,那裏式替換原則是否是和多態概念有衝突呢。後來在和朋友交流時候慢慢的有了一些感悟。故而記錄下來。
   首先在咱們的java語言中。能夠用來實現多態的方式有不少種。通常爲普通父類、抽象類和接口。而對普通父類而言。它不要用來作多態。普通的父類是自下而上的封裝共性域的一種形式。通常而言,咱們封裝普通父類,是由於有共有的屬性、方法。不須要去重寫,而是自下而上的封裝共性。所以針對普通父類中定義的方法,其實就是子類的共性方法,原理上若是不是共性的方法,就不能抽象爲父類。所以普通父類中定義且實現的方法,子類一律不要去重寫。這就能看出來裏式替換的原理。而多態通常是在抽象類或者接口層去作的。這是由於。抽象類和接口都是自上而下的定義行爲約束。例如在抽象類或者接口中,定義的抽象方法,並沒有具體實現,這就是代表子類必需要去重寫該方法來實現多態。而針對抽象類或者接口中已經定義且作了實現的方法,則就是共性定義的方法。繼承抽象類或者實現接口的類都不該該去覆蓋該方法,就直接拿來用就行了。這也是里氏替換原則的體現
相關文章
相關標籤/搜索