里氏代換原則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;
}
publicvirtual 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類之間的繼承關係違反了里氏代換原則,它們之間的繼承關係不成立,正方形不是長方形。
當執行程式的時候,長方形可以正常的改變長方形的寬度,而正方形不能改變寬度。里氏代換原則說明了我們不能亂用繼承,這裡長方形的長和寬和正方形的長和寬明顯有不同的特點,所以正方形繼承長方形是錯誤的,正確的寫法是我們可以把正方形和長方形抽象出來,再讓正方形和長方形繼承這個抽象類,從而這兩個類互不影響,各實現各的功能。