1. 程式人生 > >里氏代換原則C#詳解

里氏代換原則C#詳解

看了一大堆的資料講解關於里氏代換原則,在這裡我想分享給大家。

下面這段話來自百度百科,是這麼解釋里氏代換原則的:

里氏代換原則(Liskov Substitution Principle LSP)是面向物件設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。 LSP是繼承複用的基石,只有當子類可以替換掉父類,軟體單位的功能不受到影響時,父類才能真正被複用,而子類也能夠在父類的基礎上增加新的行為。里氏代換原則是對“開-閉”原則的補充。實現“開-閉”原則的關鍵步驟就是抽象化。而基類與子類的繼承關係就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規範。

下面舉例說明什麼是裡代換原則

例項1   正方形不是長方形

在幾何當中,正方形肯定是長方形,只不過它是特殊的長方形,四條邊都相等,利用面向物件的繼承關係,我們讓正方形繼承長方形,程式碼如下:

// C#講解里氏代換原則
// 例項名稱:正方形不是長方形

using System;

// 長方形類
class Rectangle 
{
  int length;
  int width;
  public int getLength() 
  { 
      return length; 
  }
  public int getWidth() 
  { 
      return width; 
  }
   public

 virtual void setLength(int length) 
  { 
      this.length = length;
  }
  public virtual void setWidth(int width) 
  { 
      this.width = width; 
  }
}

// 正方形類Square
class Square : Rectangle 
{
    public override void setLength(int length) 
      {
        base.setLength(length);
        base.setWidth
(length);   
      } 
      public override void setWidth(int width) 
      {
        base.setLength(width);
        base.setWidth(width);   
     }
  
}

/*
 * 由於正方形的長度和寬度必須相等,所以在方法setLength和setWidth中,
 * 對長度和寬度賦值相同。類TestRectangle是我們的軟體系統中的一個元件,
 * 它有一個resize方法要用到基類Rectangle,resize方法的功能是模擬長方形寬度逐步增長的效果
 */

//測試類TestRectangle
class TestRectangle {
      // 此方法改變長方形的寬,將寬設為比高大
      static void resize(Rectangle objRect) 
      {
          Console.WriteLine("設定寬度開始");
        while(objRect.getWidth() <= objRect.getLength()  ) 
        {
            objRect.setWidth(  objRect.getWidth () + 1 );
        }
        Console.WriteLine("設定寬度結束");
        
      }
      static void Main()
      {
          // 例項化一個長方形
          Rectangle r=new Rectangle();
          // 設長為10
          r.setLength(10);
          // 設寬為1
          r.setWidth(1);
          
          Console.WriteLine("長方形");
          Console.WriteLine("改變之前長為:"+r.getLength());
          Console.WriteLine("改變之前寬為:"+r.getWidth());
          
          // 呼叫方法改變長方形的寬
          resize(r);
          // 改變之後
          Console.WriteLine("改變之後長為:"+r.getLength());
          Console.WriteLine("改變之後寬為:"+r.getWidth());
          
          
          Rectangle s=new Square();
          
          s.setLength(10);
          s.setWidth(1);
          Console.WriteLine("正方形");
          Console.WriteLine("改變之前長為:"+s.getLength());
          Console.WriteLine("改變之前寬為:"+s.getWidth());
          
          // 呼叫方法改變正方形的寬
          resize(s);
          Console.WriteLine("改變之後長為:"+s.getLength());
          Console.WriteLine("改變之後寬為:"+s.getWidth());
      }
}

我們執行一下這段程式碼就會發現,假如我們把一個普通長方形的例項作為引數傳入resize方法,就會看到長方形寬度逐漸增長的效果,當寬度大於長度,程式碼就會停止,這種行為的結果符合我們的預期;假如我們利用里氏代換所說的,把子類的例項賦給父類,再把父類(正方形)的例項作為引數傳入resize方法後,就會看到正方形的寬度和長度都在不斷增長,程式碼會一直執行下去,直至系統產生溢位錯誤。所以,普通的長方形是適合這段程式碼的,正方形不適合。

        我們得出結論:在resize方法中,Rectangle型別的引數是不能被Square型別的引數所代替,如果進行了替換就得不到預期結果。因此,Square類和Rectangle類之間的繼承關係違反了里氏代換原則,它們之間的繼承關係不成立,正方形不是長方形。

        當執行程式的時候,長方形可以正常的改變長方形的寬度,而正方形不能改變寬度。里氏代換原則說明了我們不能亂用繼承,這裡長方形的長和寬和正方形的長和寬明顯有不同的特點,所以正方形繼承長方形是錯誤的,正確的寫法是我們可以把正方形和長方形抽象出來,再讓正方形和長方形繼承這個抽象類,從而這兩個類互不影響,各實現各的功能。